~ubuntu-branches/ubuntu/raring/udisks/raring-proposed

« back to all changes in this revision

Viewing changes to .pc/12-bogus-uevent-paths.patch/src/device.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2012-04-02 12:21:43 UTC
  • mfrom: (31.1.1 sid)
  • Revision ID: package-import@ubuntu.com-20120402122143-qlmqluwpipmru6j5
Tags: 1.0.4-5ubuntu1
* Merge with Debian unstable. Remaining Ubuntu changes:
  - debian/control: Change the "cryptsetup" suggests to a "cryptsetup-bin"
    recommends, so that LUKS functionality works by default. This change
    needs to be kept in Ubuntu until the cryptsetup package split goes into
    Debian as well. (LP: #343363)

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 <david@fubar.dk>
 
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
#ifdef HAVE_CONFIG_H
 
22
#  include "config.h"
 
23
#endif
 
24
 
 
25
#include <stdlib.h>
 
26
#include <stdio.h>
 
27
#include <unistd.h>
 
28
#include <signal.h>
 
29
#include <errno.h>
 
30
#include <string.h>
 
31
#include <sys/types.h>
 
32
#include <sys/wait.h>
 
33
#include <sys/stat.h>
 
34
#include <sys/time.h>
 
35
#include <sys/resource.h>
 
36
#include <fcntl.h>
 
37
#include <pwd.h>
 
38
#include <grp.h>
 
39
#include <stdint.h>
 
40
#include <linux/fs.h>
 
41
#include <sys/ioctl.h>
 
42
#include <linux/cdrom.h>
 
43
#include <linux/loop.h>
 
44
 
 
45
#include <glib.h>
 
46
#include <glib/gstdio.h>
 
47
#include <glib/gi18n-lib.h>
 
48
#include <glib-object.h>
 
49
#include <gio/gunixmounts.h>
 
50
#include <dbus/dbus-glib.h>
 
51
#include <dbus/dbus-glib-lowlevel.h>
 
52
#include <gudev/gudev.h>
 
53
#include <atasmart.h>
 
54
 
 
55
#include "daemon.h"
 
56
#include "device.h"
 
57
#include "device-private.h"
 
58
#include "marshal.h"
 
59
#include "mount.h"
 
60
#include "mount-monitor.h"
 
61
#include "mount-file.h"
 
62
#include "inhibitor.h"
 
63
#include "poller.h"
 
64
#include "adapter.h"
 
65
#include "port.h"
 
66
 
 
67
#include "profile.h"
 
68
 
 
69
/*--------------------------------------------------------------------------------------------------------------*/
 
70
#include "device-glue.h"
 
71
 
 
72
static void device_class_init (DeviceClass *klass);
 
73
static void device_init (Device *seat);
 
74
static void device_finalize (GObject *object);
 
75
 
 
76
static void polling_inhibitor_disconnected_cb (Inhibitor *inhibitor,
 
77
                                               Device *device);
 
78
 
 
79
static void spindown_inhibitor_disconnected_cb (Inhibitor *inhibitor,
 
80
                                                Device *device);
 
81
 
 
82
static gboolean update_info (Device *device);
 
83
static void update_info_in_idle (Device *device);
 
84
 
 
85
static void drain_pending_changes (Device *device,
 
86
                                   gboolean force_update);
 
87
 
 
88
static gboolean device_local_is_busy (Device *device,
 
89
                                      gboolean check_partitions,
 
90
                                      gboolean check_mounted,
 
91
                                      GError **error);
 
92
 
 
93
static gboolean device_local_partitions_are_busy (Device *device);
 
94
static gboolean device_local_logical_partitions_are_busy (Device *device);
 
95
static gboolean device_has_logical_partitions (Device *device);
 
96
 
 
97
static gboolean luks_get_uid_from_dm_name (const char *dm_name,
 
98
                                           uid_t *out_uid);
 
99
 
 
100
/* Returns the cleartext device. If device==NULL, unlocking failed and an error has
 
101
 * been reported back to the caller
 
102
 */
 
103
typedef void (*UnlockEncryptionHookFunc) (DBusGMethodInvocation *context,
 
104
                                          Device *device,
 
105
                                          gpointer user_data);
 
106
 
 
107
static gboolean device_luks_unlock_internal (Device *device,
 
108
                                             const char *secret,
 
109
                                             char **options,
 
110
                                             UnlockEncryptionHookFunc hook_func,
 
111
                                             gpointer hook_user_data,
 
112
                                             DBusGMethodInvocation *context);
 
113
 
 
114
/* if filesystem_create_succeeded==FALSE, mkfs failed and an error has been reported back to the caller */
 
115
typedef void (*FilesystemCreateHookFunc) (DBusGMethodInvocation *context,
 
116
                                          Device *device,
 
117
                                          gboolean filesystem_create_succeeded,
 
118
                                          gpointer user_data);
 
119
 
 
120
static gboolean device_filesystem_create_internal (Device *device,
 
121
                                                   const char *fstype,
 
122
                                                   char **options,
 
123
                                                   FilesystemCreateHookFunc hook_func,
 
124
                                                   gpointer hook_user_data,
 
125
                                                   DBusGMethodInvocation *context);
 
126
 
 
127
typedef void (*ForceRemovalCompleteFunc) (Device *device,
 
128
                                          gboolean success,
 
129
                                          gpointer user_data);
 
130
 
 
131
static void force_removal (Device *device,
 
132
                           ForceRemovalCompleteFunc callback,
 
133
                           gpointer user_data);
 
134
 
 
135
static void force_unmount (Device *device,
 
136
                           ForceRemovalCompleteFunc callback,
 
137
                           gpointer user_data);
 
138
 
 
139
static void force_luks_teardown (Device *device,
 
140
                                 Device *cleartext_device,
 
141
                                 ForceRemovalCompleteFunc callback,
 
142
                                 gpointer user_data);
 
143
 
 
144
static gboolean
 
145
ptr_array_has_string (GPtrArray *p, const gchar *str)
 
146
{
 
147
  guint n;
 
148
  gboolean ret;
 
149
 
 
150
  ret = FALSE;
 
151
  for (n = 0; n < p->len; n++)
 
152
    {
 
153
      if (g_strcmp0 (p->pdata[n], str) == 0)
 
154
        {
 
155
          ret = TRUE;
 
156
          goto out;
 
157
        }
 
158
    }
 
159
 
 
160
 out:
 
161
  return ret;
 
162
}
 
163
 
 
164
/* TODO: this is kinda a hack */
 
165
static const gchar *
 
166
get_dmmp_device_node (Device *device)
 
167
{
 
168
  static gchar buf[1024];
 
169
 
 
170
  g_assert (device->priv->device_is_linux_dmmp);
 
171
  g_snprintf (buf, sizeof (buf), "/dev/mapper/%s", device->priv->linux_dmmp_name);
 
172
  return buf;
 
173
}
 
174
 
 
175
enum
 
176
  {
 
177
    PROP_0,
 
178
    PROP_NATIVE_PATH,
 
179
 
 
180
    PROP_DEVICE_AUTOMOUNT_HINT,
 
181
    PROP_DEVICE_DETECTION_TIME,
 
182
    PROP_DEVICE_MEDIA_DETECTION_TIME,
 
183
    PROP_DEVICE_MAJOR,
 
184
    PROP_DEVICE_MINOR,
 
185
    PROP_DEVICE_FILE,
 
186
    PROP_DEVICE_FILE_PRESENTATION,
 
187
    PROP_DEVICE_FILE_BY_ID,
 
188
    PROP_DEVICE_FILE_BY_PATH,
 
189
    PROP_DEVICE_IS_SYSTEM_INTERNAL,
 
190
    PROP_DEVICE_IS_PARTITION,
 
191
    PROP_DEVICE_IS_PARTITION_TABLE,
 
192
    PROP_DEVICE_IS_REMOVABLE,
 
193
    PROP_DEVICE_IS_MEDIA_AVAILABLE,
 
194
    PROP_DEVICE_IS_MEDIA_CHANGE_DETECTED,
 
195
    PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_POLLING,
 
196
    PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_INHIBITABLE,
 
197
    PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_INHIBITED,
 
198
    PROP_DEVICE_IS_READ_ONLY,
 
199
    PROP_DEVICE_IS_DRIVE,
 
200
    PROP_DEVICE_IS_OPTICAL_DISC,
 
201
    PROP_DEVICE_IS_LUKS,
 
202
    PROP_DEVICE_IS_LUKS_CLEARTEXT,
 
203
    PROP_DEVICE_IS_LINUX_MD_COMPONENT,
 
204
    PROP_DEVICE_IS_LINUX_MD,
 
205
    PROP_DEVICE_IS_LINUX_LVM2_LV,
 
206
    PROP_DEVICE_IS_LINUX_LVM2_PV,
 
207
    PROP_DEVICE_IS_LINUX_DMMP,
 
208
    PROP_DEVICE_IS_LINUX_DMMP_COMPONENT,
 
209
    PROP_DEVICE_IS_LINUX_LOOP,
 
210
    PROP_DEVICE_SIZE,
 
211
    PROP_DEVICE_BLOCK_SIZE,
 
212
    PROP_DEVICE_IS_MOUNTED,
 
213
    PROP_DEVICE_MOUNT_PATHS,
 
214
    PROP_DEVICE_MOUNTED_BY_UID,
 
215
    PROP_DEVICE_PRESENTATION_HIDE,
 
216
    PROP_DEVICE_PRESENTATION_NOPOLICY,
 
217
    PROP_DEVICE_PRESENTATION_NAME,
 
218
    PROP_DEVICE_PRESENTATION_ICON_NAME,
 
219
 
 
220
    PROP_JOB_IN_PROGRESS,
 
221
    PROP_JOB_ID,
 
222
    PROP_JOB_INITIATED_BY_UID,
 
223
    PROP_JOB_IS_CANCELLABLE,
 
224
    PROP_JOB_PERCENTAGE,
 
225
 
 
226
    PROP_ID_USAGE,
 
227
    PROP_ID_TYPE,
 
228
    PROP_ID_VERSION,
 
229
    PROP_ID_UUID,
 
230
    PROP_ID_LABEL,
 
231
 
 
232
    PROP_PARTITION_SLAVE,
 
233
    PROP_PARTITION_SCHEME,
 
234
    PROP_PARTITION_TYPE,
 
235
    PROP_PARTITION_LABEL,
 
236
    PROP_PARTITION_UUID,
 
237
    PROP_PARTITION_FLAGS,
 
238
    PROP_PARTITION_NUMBER,
 
239
    PROP_PARTITION_OFFSET,
 
240
    PROP_PARTITION_SIZE,
 
241
    PROP_PARTITION_ALIGNMENT_OFFSET,
 
242
 
 
243
    PROP_PARTITION_TABLE_SCHEME,
 
244
    PROP_PARTITION_TABLE_COUNT,
 
245
 
 
246
    PROP_LUKS_HOLDER,
 
247
 
 
248
    PROP_LUKS_CLEARTEXT_SLAVE,
 
249
    PROP_LUKS_CLEARTEXT_UNLOCKED_BY_UID,
 
250
 
 
251
    PROP_DRIVE_VENDOR,
 
252
    PROP_DRIVE_MODEL,
 
253
    PROP_DRIVE_REVISION,
 
254
    PROP_DRIVE_SERIAL,
 
255
    PROP_DRIVE_WWN,
 
256
    PROP_DRIVE_CONNECTION_INTERFACE,
 
257
    PROP_DRIVE_CONNECTION_SPEED,
 
258
    PROP_DRIVE_MEDIA_COMPATIBILITY,
 
259
    PROP_DRIVE_MEDIA,
 
260
    PROP_DRIVE_IS_MEDIA_EJECTABLE,
 
261
    PROP_DRIVE_CAN_DETACH,
 
262
    PROP_DRIVE_CAN_SPINDOWN,
 
263
    PROP_DRIVE_IS_ROTATIONAL,
 
264
    PROP_DRIVE_ROTATION_RATE,
 
265
    PROP_DRIVE_WRITE_CACHE,
 
266
    PROP_DRIVE_ADAPTER,
 
267
    PROP_DRIVE_PORTS,
 
268
    PROP_DRIVE_SIMILAR_DEVICES,
 
269
 
 
270
    PROP_OPTICAL_DISC_IS_BLANK,
 
271
    PROP_OPTICAL_DISC_IS_APPENDABLE,
 
272
    PROP_OPTICAL_DISC_IS_CLOSED,
 
273
    PROP_OPTICAL_DISC_NUM_TRACKS,
 
274
    PROP_OPTICAL_DISC_NUM_AUDIO_TRACKS,
 
275
    PROP_OPTICAL_DISC_NUM_SESSIONS,
 
276
 
 
277
    PROP_DRIVE_ATA_SMART_IS_AVAILABLE,
 
278
    PROP_DRIVE_ATA_SMART_TIME_COLLECTED,
 
279
    PROP_DRIVE_ATA_SMART_STATUS,
 
280
    PROP_DRIVE_ATA_SMART_BLOB,
 
281
 
 
282
    PROP_LINUX_MD_COMPONENT_LEVEL,
 
283
    PROP_LINUX_MD_COMPONENT_POSITION,
 
284
    PROP_LINUX_MD_COMPONENT_NUM_RAID_DEVICES,
 
285
    PROP_LINUX_MD_COMPONENT_UUID,
 
286
    PROP_LINUX_MD_COMPONENT_HOME_HOST,
 
287
    PROP_LINUX_MD_COMPONENT_NAME,
 
288
    PROP_LINUX_MD_COMPONENT_VERSION,
 
289
    PROP_LINUX_MD_COMPONENT_HOLDER,
 
290
    PROP_LINUX_MD_COMPONENT_STATE,
 
291
 
 
292
    PROP_LINUX_MD_STATE,
 
293
    PROP_LINUX_MD_LEVEL,
 
294
    PROP_LINUX_MD_NUM_RAID_DEVICES,
 
295
    PROP_LINUX_MD_UUID,
 
296
    PROP_LINUX_MD_HOME_HOST,
 
297
    PROP_LINUX_MD_NAME,
 
298
    PROP_LINUX_MD_VERSION,
 
299
    PROP_LINUX_MD_SLAVES,
 
300
    PROP_LINUX_MD_IS_DEGRADED,
 
301
    PROP_LINUX_MD_SYNC_ACTION,
 
302
    PROP_LINUX_MD_SYNC_PERCENTAGE,
 
303
    PROP_LINUX_MD_SYNC_SPEED,
 
304
 
 
305
    PROP_LINUX_LVM2_LV_NAME,
 
306
    PROP_LINUX_LVM2_LV_UUID,
 
307
    PROP_LINUX_LVM2_LV_GROUP_NAME,
 
308
    PROP_LINUX_LVM2_LV_GROUP_UUID,
 
309
 
 
310
    PROP_LINUX_LVM2_PV_UUID,
 
311
    PROP_LINUX_LVM2_PV_NUM_METADATA_AREAS,
 
312
    PROP_LINUX_LVM2_PV_GROUP_NAME,
 
313
    PROP_LINUX_LVM2_PV_GROUP_UUID,
 
314
    PROP_LINUX_LVM2_PV_GROUP_SIZE,
 
315
    PROP_LINUX_LVM2_PV_GROUP_UNALLOCATED_SIZE,
 
316
    PROP_LINUX_LVM2_PV_GROUP_SEQUENCE_NUMBER,
 
317
    PROP_LINUX_LVM2_PV_GROUP_EXTENT_SIZE,
 
318
    PROP_LINUX_LVM2_PV_GROUP_PHYSICAL_VOLUMES,
 
319
    PROP_LINUX_LVM2_PV_GROUP_LOGICAL_VOLUMES,
 
320
 
 
321
    PROP_LINUX_DMMP_COMPONENT_HOLDER,
 
322
 
 
323
    PROP_LINUX_DMMP_NAME,
 
324
    PROP_LINUX_DMMP_SLAVES,
 
325
    PROP_LINUX_DMMP_PARAMETERS,
 
326
 
 
327
    PROP_LINUX_LOOP_FILENAME,
 
328
  };
 
329
 
 
330
enum
 
331
  {
 
332
    CHANGED_SIGNAL,
 
333
    JOB_CHANGED_SIGNAL,
 
334
    LAST_SIGNAL,
 
335
  };
 
336
 
 
337
static guint signals[LAST_SIGNAL] = { 0 };
 
338
 
 
339
G_DEFINE_TYPE (Device, device, G_TYPE_OBJECT)
 
340
 
 
341
#define DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_DEVICE, DevicePrivate))
 
342
 
 
343
static GObject *
 
344
device_constructor (GType type,
 
345
                    guint n_construct_properties,
 
346
                    GObjectConstructParam *construct_properties)
 
347
{
 
348
  Device *device;
 
349
 
 
350
  device = DEVICE (G_OBJECT_CLASS (device_parent_class)->constructor (type,
 
351
                                                                      n_construct_properties,
 
352
                                                                      construct_properties));
 
353
  return G_OBJECT (device);
 
354
}
 
355
 
 
356
static void
 
357
get_property (GObject *object,
 
358
              guint prop_id,
 
359
              GValue *value,
 
360
              GParamSpec *pspec)
 
361
{
 
362
  Device *device = DEVICE (object);
 
363
 
 
364
  switch (prop_id)
 
365
    {
 
366
    case PROP_NATIVE_PATH:
 
367
      g_value_set_string (value, device->priv->native_path);
 
368
      break;
 
369
 
 
370
    case PROP_DEVICE_DETECTION_TIME:
 
371
      g_value_set_uint64 (value, device->priv->device_detection_time);
 
372
      break;
 
373
    case PROP_DEVICE_MEDIA_DETECTION_TIME:
 
374
      g_value_set_uint64 (value, device->priv->device_media_detection_time);
 
375
      break;
 
376
    case PROP_DEVICE_MAJOR:
 
377
      g_value_set_int64 (value, major (device->priv->dev));
 
378
      break;
 
379
    case PROP_DEVICE_MINOR:
 
380
      g_value_set_int64 (value, minor (device->priv->dev));
 
381
      break;
 
382
    case PROP_DEVICE_FILE:
 
383
      g_value_set_string (value, device->priv->device_file);
 
384
      break;
 
385
    case PROP_DEVICE_AUTOMOUNT_HINT:
 
386
      g_value_set_string (value, device->priv->device_automount_hint);
 
387
      break;
 
388
    case PROP_DEVICE_FILE_PRESENTATION:
 
389
      if (device->priv->device_file_presentation != NULL)
 
390
        g_value_set_string (value, device->priv->device_file_presentation);
 
391
      else
 
392
        g_value_set_string (value, device->priv->device_file);
 
393
      break;
 
394
    case PROP_DEVICE_FILE_BY_ID:
 
395
      g_value_set_boxed (value, device->priv->device_file_by_id);
 
396
      break;
 
397
    case PROP_DEVICE_FILE_BY_PATH:
 
398
      g_value_set_boxed (value, device->priv->device_file_by_path);
 
399
      break;
 
400
    case PROP_DEVICE_IS_SYSTEM_INTERNAL:
 
401
      g_value_set_boolean (value, device->priv->device_is_system_internal);
 
402
      break;
 
403
    case PROP_DEVICE_IS_PARTITION:
 
404
      g_value_set_boolean (value, device->priv->device_is_partition);
 
405
      break;
 
406
    case PROP_DEVICE_IS_PARTITION_TABLE:
 
407
      g_value_set_boolean (value, device->priv->device_is_partition_table);
 
408
      break;
 
409
    case PROP_DEVICE_IS_REMOVABLE:
 
410
      g_value_set_boolean (value, device->priv->device_is_removable);
 
411
      break;
 
412
    case PROP_DEVICE_IS_MEDIA_AVAILABLE:
 
413
      g_value_set_boolean (value, device->priv->device_is_media_available);
 
414
      break;
 
415
    case PROP_DEVICE_IS_MEDIA_CHANGE_DETECTED:
 
416
      g_value_set_boolean (value, device->priv->device_is_media_change_detected);
 
417
      break;
 
418
    case PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_POLLING:
 
419
      g_value_set_boolean (value, device->priv->device_is_media_change_detection_polling);
 
420
      break;
 
421
    case PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_INHIBITABLE:
 
422
      g_value_set_boolean (value, device->priv->device_is_media_change_detection_inhibitable);
 
423
      break;
 
424
    case PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_INHIBITED:
 
425
      g_value_set_boolean (value, device->priv->device_is_media_change_detection_inhibited);
 
426
      break;
 
427
    case PROP_DEVICE_IS_READ_ONLY:
 
428
      g_value_set_boolean (value, device->priv->device_is_read_only);
 
429
      break;
 
430
    case PROP_DEVICE_IS_DRIVE:
 
431
      g_value_set_boolean (value, device->priv->device_is_drive);
 
432
      break;
 
433
    case PROP_DEVICE_IS_OPTICAL_DISC:
 
434
      g_value_set_boolean (value, device->priv->device_is_optical_disc);
 
435
      break;
 
436
    case PROP_DEVICE_IS_LUKS:
 
437
      g_value_set_boolean (value, device->priv->device_is_luks);
 
438
      break;
 
439
    case PROP_DEVICE_IS_LUKS_CLEARTEXT:
 
440
      g_value_set_boolean (value, device->priv->device_is_luks_cleartext);
 
441
      break;
 
442
    case PROP_DEVICE_IS_LINUX_MD_COMPONENT:
 
443
      g_value_set_boolean (value, device->priv->device_is_linux_md_component);
 
444
      break;
 
445
    case PROP_DEVICE_IS_LINUX_MD:
 
446
      g_value_set_boolean (value, device->priv->device_is_linux_md);
 
447
      break;
 
448
    case PROP_DEVICE_IS_LINUX_LVM2_LV:
 
449
      g_value_set_boolean (value, device->priv->device_is_linux_lvm2_lv);
 
450
      break;
 
451
    case PROP_DEVICE_IS_LINUX_LVM2_PV:
 
452
      g_value_set_boolean (value, device->priv->device_is_linux_lvm2_pv);
 
453
      break;
 
454
    case PROP_DEVICE_IS_LINUX_DMMP:
 
455
      g_value_set_boolean (value, device->priv->device_is_linux_dmmp);
 
456
      break;
 
457
    case PROP_DEVICE_IS_LINUX_DMMP_COMPONENT:
 
458
      g_value_set_boolean (value, device->priv->device_is_linux_dmmp_component);
 
459
      break;
 
460
    case PROP_DEVICE_IS_LINUX_LOOP:
 
461
      g_value_set_boolean (value, device->priv->device_is_linux_loop);
 
462
      break;
 
463
    case PROP_DEVICE_SIZE:
 
464
      g_value_set_uint64 (value, device->priv->device_size);
 
465
      break;
 
466
    case PROP_DEVICE_BLOCK_SIZE:
 
467
      g_value_set_uint64 (value, device->priv->device_block_size);
 
468
      break;
 
469
    case PROP_DEVICE_IS_MOUNTED:
 
470
      g_value_set_boolean (value, device->priv->device_is_mounted);
 
471
      break;
 
472
    case PROP_DEVICE_MOUNT_PATHS:
 
473
      g_value_set_boxed (value, device->priv->device_mount_paths);
 
474
      break;
 
475
    case PROP_DEVICE_MOUNTED_BY_UID:
 
476
      g_value_set_uint (value, device->priv->device_mounted_by_uid);
 
477
      break;
 
478
    case PROP_DEVICE_PRESENTATION_HIDE:
 
479
      g_value_set_boolean (value, device->priv->device_presentation_hide);
 
480
      break;
 
481
    case PROP_DEVICE_PRESENTATION_NOPOLICY:
 
482
      g_value_set_boolean (value, device->priv->device_presentation_nopolicy);
 
483
      break;
 
484
    case PROP_DEVICE_PRESENTATION_NAME:
 
485
      g_value_set_string (value, device->priv->device_presentation_name);
 
486
      break;
 
487
    case PROP_DEVICE_PRESENTATION_ICON_NAME:
 
488
      g_value_set_string (value, device->priv->device_presentation_icon_name);
 
489
      break;
 
490
 
 
491
    case PROP_JOB_IN_PROGRESS:
 
492
      g_value_set_boolean (value, device->priv->job_in_progress);
 
493
      break;
 
494
    case PROP_JOB_ID:
 
495
      g_value_set_string (value, device->priv->job_id);
 
496
      break;
 
497
    case PROP_JOB_INITIATED_BY_UID:
 
498
      g_value_set_uint (value, device->priv->job_initiated_by_uid);
 
499
      break;
 
500
    case PROP_JOB_IS_CANCELLABLE:
 
501
      g_value_set_boolean (value, device->priv->job_is_cancellable);
 
502
      break;
 
503
    case PROP_JOB_PERCENTAGE:
 
504
      g_value_set_double (value, device->priv->job_percentage);
 
505
      break;
 
506
 
 
507
    case PROP_ID_USAGE:
 
508
      g_value_set_string (value, device->priv->id_usage);
 
509
      break;
 
510
    case PROP_ID_TYPE:
 
511
      g_value_set_string (value, device->priv->id_type);
 
512
      break;
 
513
    case PROP_ID_VERSION:
 
514
      g_value_set_string (value, device->priv->id_version);
 
515
      break;
 
516
    case PROP_ID_UUID:
 
517
      g_value_set_string (value, device->priv->id_uuid);
 
518
      break;
 
519
    case PROP_ID_LABEL:
 
520
      g_value_set_string (value, device->priv->id_label);
 
521
      break;
 
522
 
 
523
    case PROP_PARTITION_SLAVE:
 
524
      if (device->priv->partition_slave != NULL)
 
525
        g_value_set_boxed (value, device->priv->partition_slave);
 
526
      else
 
527
        g_value_set_boxed (value, "/");
 
528
      break;
 
529
    case PROP_PARTITION_SCHEME:
 
530
      g_value_set_string (value, device->priv->partition_scheme);
 
531
      break;
 
532
    case PROP_PARTITION_TYPE:
 
533
      g_value_set_string (value, device->priv->partition_type);
 
534
      break;
 
535
    case PROP_PARTITION_LABEL:
 
536
      g_value_set_string (value, device->priv->partition_label);
 
537
      break;
 
538
    case PROP_PARTITION_UUID:
 
539
      g_value_set_string (value, device->priv->partition_uuid);
 
540
      break;
 
541
    case PROP_PARTITION_FLAGS:
 
542
      g_value_set_boxed (value, device->priv->partition_flags);
 
543
      break;
 
544
    case PROP_PARTITION_NUMBER:
 
545
      g_value_set_int (value, device->priv->partition_number);
 
546
      break;
 
547
    case PROP_PARTITION_OFFSET:
 
548
      g_value_set_uint64 (value, device->priv->partition_offset);
 
549
      break;
 
550
    case PROP_PARTITION_SIZE:
 
551
      g_value_set_uint64 (value, device->priv->partition_size);
 
552
      break;
 
553
    case PROP_PARTITION_ALIGNMENT_OFFSET:
 
554
      g_value_set_uint64 (value, device->priv->partition_alignment_offset);
 
555
      break;
 
556
 
 
557
    case PROP_PARTITION_TABLE_SCHEME:
 
558
      g_value_set_string (value, device->priv->partition_table_scheme);
 
559
      break;
 
560
    case PROP_PARTITION_TABLE_COUNT:
 
561
      g_value_set_int (value, device->priv->partition_table_count);
 
562
      break;
 
563
 
 
564
    case PROP_LUKS_HOLDER:
 
565
      if (device->priv->luks_holder != NULL)
 
566
        g_value_set_boxed (value, device->priv->luks_holder);
 
567
      else
 
568
        g_value_set_boxed (value, "/");
 
569
      break;
 
570
 
 
571
    case PROP_LUKS_CLEARTEXT_SLAVE:
 
572
      if (device->priv->luks_cleartext_slave != NULL)
 
573
        g_value_set_boxed (value, device->priv->luks_cleartext_slave);
 
574
      else
 
575
        g_value_set_boxed (value, "/");
 
576
      break;
 
577
    case PROP_LUKS_CLEARTEXT_UNLOCKED_BY_UID:
 
578
      g_value_set_uint (value, device->priv->luks_cleartext_unlocked_by_uid);
 
579
      break;
 
580
 
 
581
    case PROP_DRIVE_VENDOR:
 
582
      g_value_set_string (value, device->priv->drive_vendor);
 
583
      break;
 
584
    case PROP_DRIVE_MODEL:
 
585
      g_value_set_string (value, device->priv->drive_model);
 
586
      break;
 
587
    case PROP_DRIVE_REVISION:
 
588
      g_value_set_string (value, device->priv->drive_revision);
 
589
      break;
 
590
    case PROP_DRIVE_SERIAL:
 
591
      g_value_set_string (value, device->priv->drive_serial);
 
592
      break;
 
593
    case PROP_DRIVE_WWN:
 
594
      g_value_set_string (value, device->priv->drive_wwn);
 
595
      break;
 
596
    case PROP_DRIVE_CONNECTION_INTERFACE:
 
597
      g_value_set_string (value, device->priv->drive_connection_interface);
 
598
      break;
 
599
    case PROP_DRIVE_CONNECTION_SPEED:
 
600
      g_value_set_uint64 (value, device->priv->drive_connection_speed);
 
601
      break;
 
602
    case PROP_DRIVE_MEDIA_COMPATIBILITY:
 
603
      g_value_set_boxed (value, device->priv->drive_media_compatibility);
 
604
      break;
 
605
    case PROP_DRIVE_MEDIA:
 
606
      g_value_set_string (value, device->priv->drive_media);
 
607
      break;
 
608
    case PROP_DRIVE_IS_MEDIA_EJECTABLE:
 
609
      g_value_set_boolean (value, device->priv->drive_is_media_ejectable);
 
610
      break;
 
611
    case PROP_DRIVE_CAN_DETACH:
 
612
      g_value_set_boolean (value, device->priv->drive_can_detach);
 
613
      break;
 
614
    case PROP_DRIVE_CAN_SPINDOWN:
 
615
      g_value_set_boolean (value, device->priv->drive_can_spindown);
 
616
      break;
 
617
    case PROP_DRIVE_IS_ROTATIONAL:
 
618
      g_value_set_boolean (value, device->priv->drive_is_rotational);
 
619
      break;
 
620
    case PROP_DRIVE_WRITE_CACHE:
 
621
      g_value_set_string (value, device->priv->drive_write_cache);
 
622
      break;
 
623
    case PROP_DRIVE_ROTATION_RATE:
 
624
      g_value_set_uint (value, device->priv->drive_rotation_rate);
 
625
      break;
 
626
    case PROP_DRIVE_ADAPTER:
 
627
      if (device->priv->drive_adapter != NULL)
 
628
        g_value_set_boxed (value, device->priv->drive_adapter);
 
629
      else
 
630
        g_value_set_boxed (value, "/");
 
631
      break;
 
632
    case PROP_DRIVE_PORTS:
 
633
      g_value_set_boxed (value, device->priv->drive_ports);
 
634
      break;
 
635
    case PROP_DRIVE_SIMILAR_DEVICES:
 
636
      g_value_set_boxed (value, device->priv->drive_similar_devices);
 
637
      break;
 
638
 
 
639
    case PROP_OPTICAL_DISC_IS_BLANK:
 
640
      g_value_set_boolean (value, device->priv->optical_disc_is_blank);
 
641
      break;
 
642
    case PROP_OPTICAL_DISC_IS_APPENDABLE:
 
643
      g_value_set_boolean (value, device->priv->optical_disc_is_appendable);
 
644
      break;
 
645
    case PROP_OPTICAL_DISC_IS_CLOSED:
 
646
      g_value_set_boolean (value, device->priv->optical_disc_is_closed);
 
647
      break;
 
648
    case PROP_OPTICAL_DISC_NUM_TRACKS:
 
649
      g_value_set_uint (value, device->priv->optical_disc_num_tracks);
 
650
      break;
 
651
    case PROP_OPTICAL_DISC_NUM_AUDIO_TRACKS:
 
652
      g_value_set_uint (value, device->priv->optical_disc_num_audio_tracks);
 
653
      break;
 
654
    case PROP_OPTICAL_DISC_NUM_SESSIONS:
 
655
      g_value_set_uint (value, device->priv->optical_disc_num_sessions);
 
656
      break;
 
657
 
 
658
    case PROP_DRIVE_ATA_SMART_IS_AVAILABLE:
 
659
      g_value_set_boolean (value, device->priv->drive_ata_smart_is_available);
 
660
      break;
 
661
    case PROP_DRIVE_ATA_SMART_TIME_COLLECTED:
 
662
      g_value_set_uint64 (value, device->priv->drive_ata_smart_time_collected);
 
663
      break;
 
664
    case PROP_DRIVE_ATA_SMART_STATUS:
 
665
      {
 
666
        const gchar *status;
 
667
        if (device->priv->drive_ata_smart_status == (SkSmartOverall) - 1)
 
668
          status = "";
 
669
        else
 
670
          status = sk_smart_overall_to_string (device->priv->drive_ata_smart_status);
 
671
        g_value_set_string (value, status);
 
672
      }
 
673
      break;
 
674
    case PROP_DRIVE_ATA_SMART_BLOB:
 
675
      {
 
676
        GArray *a;
 
677
        a = g_array_new (FALSE, FALSE, 1);
 
678
        if (device->priv->drive_ata_smart_blob != NULL)
 
679
          {
 
680
            g_array_append_vals (a, device->priv->drive_ata_smart_blob, device->priv->drive_ata_smart_blob_size);
 
681
          }
 
682
        g_value_set_boxed (value, a);
 
683
        g_array_unref (a);
 
684
      }
 
685
      break;
 
686
 
 
687
    case PROP_LINUX_MD_COMPONENT_LEVEL:
 
688
      g_value_set_string (value, device->priv->linux_md_component_level);
 
689
      break;
 
690
    case PROP_LINUX_MD_COMPONENT_POSITION:
 
691
      g_value_set_int (value, device->priv->linux_md_component_position);
 
692
      break;
 
693
    case PROP_LINUX_MD_COMPONENT_NUM_RAID_DEVICES:
 
694
      g_value_set_int (value, device->priv->linux_md_component_num_raid_devices);
 
695
      break;
 
696
    case PROP_LINUX_MD_COMPONENT_UUID:
 
697
      g_value_set_string (value, device->priv->linux_md_component_uuid);
 
698
      break;
 
699
    case PROP_LINUX_MD_COMPONENT_HOME_HOST:
 
700
      g_value_set_string (value, device->priv->linux_md_component_home_host);
 
701
      break;
 
702
    case PROP_LINUX_MD_COMPONENT_NAME:
 
703
      g_value_set_string (value, device->priv->linux_md_component_name);
 
704
      break;
 
705
    case PROP_LINUX_MD_COMPONENT_VERSION:
 
706
      g_value_set_string (value, device->priv->linux_md_component_version);
 
707
      break;
 
708
    case PROP_LINUX_MD_COMPONENT_HOLDER:
 
709
      if (device->priv->linux_md_component_holder != NULL)
 
710
        g_value_set_boxed (value, device->priv->linux_md_component_holder);
 
711
      else
 
712
        g_value_set_boxed (value, "/");
 
713
      break;
 
714
    case PROP_LINUX_MD_COMPONENT_STATE:
 
715
      g_value_set_boxed (value, device->priv->linux_md_component_state);
 
716
      break;
 
717
 
 
718
    case PROP_LINUX_MD_STATE:
 
719
      g_value_set_string (value, device->priv->linux_md_state);
 
720
      break;
 
721
    case PROP_LINUX_MD_LEVEL:
 
722
      g_value_set_string (value, device->priv->linux_md_level);
 
723
      break;
 
724
    case PROP_LINUX_MD_NUM_RAID_DEVICES:
 
725
      g_value_set_int (value, device->priv->linux_md_num_raid_devices);
 
726
      break;
 
727
    case PROP_LINUX_MD_UUID:
 
728
      g_value_set_string (value, device->priv->linux_md_uuid);
 
729
      break;
 
730
    case PROP_LINUX_MD_HOME_HOST:
 
731
      g_value_set_string (value, device->priv->linux_md_home_host);
 
732
      break;
 
733
    case PROP_LINUX_MD_NAME:
 
734
      g_value_set_string (value, device->priv->linux_md_name);
 
735
      break;
 
736
    case PROP_LINUX_MD_VERSION:
 
737
      g_value_set_string (value, device->priv->linux_md_version);
 
738
      break;
 
739
    case PROP_LINUX_MD_SLAVES:
 
740
      g_value_set_boxed (value, device->priv->linux_md_slaves);
 
741
      break;
 
742
    case PROP_LINUX_MD_IS_DEGRADED:
 
743
      g_value_set_boolean (value, device->priv->linux_md_is_degraded);
 
744
      break;
 
745
    case PROP_LINUX_MD_SYNC_ACTION:
 
746
      g_value_set_string (value, device->priv->linux_md_sync_action);
 
747
      break;
 
748
    case PROP_LINUX_MD_SYNC_PERCENTAGE:
 
749
      g_value_set_double (value, device->priv->linux_md_sync_percentage);
 
750
      break;
 
751
    case PROP_LINUX_MD_SYNC_SPEED:
 
752
      g_value_set_uint64 (value, device->priv->linux_md_sync_speed);
 
753
      break;
 
754
 
 
755
    case PROP_LINUX_LVM2_LV_NAME:
 
756
      g_value_set_string (value, device->priv->linux_lvm2_lv_name);
 
757
      break;
 
758
    case PROP_LINUX_LVM2_LV_UUID:
 
759
      g_value_set_string (value, device->priv->linux_lvm2_lv_uuid);
 
760
      break;
 
761
    case PROP_LINUX_LVM2_LV_GROUP_NAME:
 
762
      g_value_set_string (value, device->priv->linux_lvm2_lv_group_name);
 
763
      break;
 
764
    case PROP_LINUX_LVM2_LV_GROUP_UUID:
 
765
      g_value_set_string (value, device->priv->linux_lvm2_lv_group_uuid);
 
766
      break;
 
767
 
 
768
    case PROP_LINUX_LVM2_PV_UUID:
 
769
      g_value_set_string (value, device->priv->linux_lvm2_pv_uuid);
 
770
      break;
 
771
    case PROP_LINUX_LVM2_PV_NUM_METADATA_AREAS:
 
772
      g_value_set_uint (value, device->priv->linux_lvm2_pv_num_metadata_areas);
 
773
      break;
 
774
    case PROP_LINUX_LVM2_PV_GROUP_NAME:
 
775
      g_value_set_string (value, device->priv->linux_lvm2_pv_group_name);
 
776
      break;
 
777
    case PROP_LINUX_LVM2_PV_GROUP_UUID:
 
778
      g_value_set_string (value, device->priv->linux_lvm2_pv_group_uuid);
 
779
      break;
 
780
    case PROP_LINUX_LVM2_PV_GROUP_SIZE:
 
781
      g_value_set_uint64 (value, device->priv->linux_lvm2_pv_group_size);
 
782
      break;
 
783
    case PROP_LINUX_LVM2_PV_GROUP_UNALLOCATED_SIZE:
 
784
      g_value_set_uint64 (value, device->priv->linux_lvm2_pv_group_unallocated_size);
 
785
      break;
 
786
    case PROP_LINUX_LVM2_PV_GROUP_SEQUENCE_NUMBER:
 
787
      g_value_set_uint64 (value, device->priv->linux_lvm2_pv_group_sequence_number);
 
788
      break;
 
789
    case PROP_LINUX_LVM2_PV_GROUP_EXTENT_SIZE:
 
790
      g_value_set_uint64 (value, device->priv->linux_lvm2_pv_group_extent_size);
 
791
      break;
 
792
    case PROP_LINUX_LVM2_PV_GROUP_PHYSICAL_VOLUMES:
 
793
      g_value_set_boxed (value, device->priv->linux_lvm2_pv_group_physical_volumes);
 
794
      break;
 
795
    case PROP_LINUX_LVM2_PV_GROUP_LOGICAL_VOLUMES:
 
796
      g_value_set_boxed (value, device->priv->linux_lvm2_pv_group_logical_volumes);
 
797
      break;
 
798
 
 
799
    case PROP_LINUX_DMMP_COMPONENT_HOLDER:
 
800
      if (device->priv->linux_dmmp_component_holder != NULL)
 
801
        g_value_set_boxed (value, device->priv->linux_dmmp_component_holder);
 
802
      else
 
803
        g_value_set_boxed (value, "/");
 
804
      break;
 
805
 
 
806
    case PROP_LINUX_DMMP_NAME:
 
807
      g_value_set_string (value, device->priv->linux_dmmp_name);
 
808
      break;
 
809
 
 
810
    case PROP_LINUX_DMMP_PARAMETERS:
 
811
      g_value_set_string (value, device->priv->linux_dmmp_parameters);
 
812
      break;
 
813
 
 
814
    case PROP_LINUX_DMMP_SLAVES:
 
815
      g_value_set_boxed (value, device->priv->linux_dmmp_slaves);
 
816
      break;
 
817
 
 
818
    case PROP_LINUX_LOOP_FILENAME:
 
819
      g_value_set_string (value, device->priv->linux_loop_filename);
 
820
      break;
 
821
 
 
822
    default:
 
823
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
824
      break;
 
825
    }
 
826
}
 
827
 
 
828
static void
 
829
device_class_init (DeviceClass *klass)
 
830
{
 
831
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
832
 
 
833
  object_class->constructor = device_constructor;
 
834
  object_class->finalize = device_finalize;
 
835
  object_class->get_property = get_property;
 
836
 
 
837
  g_type_class_add_private (klass, sizeof(DevicePrivate));
 
838
 
 
839
  signals[CHANGED_SIGNAL] = g_signal_new ("changed",
 
840
                                          G_OBJECT_CLASS_TYPE (klass),
 
841
                                          G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
 
842
                                          0,
 
843
                                          NULL,
 
844
                                          NULL,
 
845
                                          g_cclosure_marshal_VOID__VOID,
 
846
                                          G_TYPE_NONE,
 
847
                                          0);
 
848
 
 
849
  signals[JOB_CHANGED_SIGNAL] = g_signal_new ("job-changed",
 
850
                                              G_OBJECT_CLASS_TYPE (klass),
 
851
                                              G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
 
852
                                              0,
 
853
                                              NULL,
 
854
                                              NULL,
 
855
                                              marshal_VOID__BOOLEAN_STRING_UINT_BOOLEAN_DOUBLE,
 
856
                                              G_TYPE_NONE,
 
857
                                              5,
 
858
                                              G_TYPE_BOOLEAN,
 
859
                                              G_TYPE_STRING,
 
860
                                              G_TYPE_UINT,
 
861
                                              G_TYPE_BOOLEAN,
 
862
                                              G_TYPE_DOUBLE);
 
863
 
 
864
  dbus_g_object_type_install_info (TYPE_DEVICE, &dbus_glib_device_object_info);
 
865
 
 
866
  g_object_class_install_property (object_class, PROP_NATIVE_PATH, g_param_spec_string ("native-path",
 
867
                                                                                        NULL,
 
868
                                                                                        NULL,
 
869
                                                                                        NULL,
 
870
                                                                                        G_PARAM_READABLE));
 
871
 
 
872
  g_object_class_install_property (object_class,
 
873
                                   PROP_DEVICE_AUTOMOUNT_HINT,
 
874
                                   g_param_spec_string ("device-automount-hint",
 
875
                                                        NULL,
 
876
                                                        NULL,
 
877
                                                        NULL,
 
878
                                                        G_PARAM_READABLE));
 
879
 
 
880
  g_object_class_install_property (object_class,
 
881
                                   PROP_DEVICE_DETECTION_TIME,
 
882
                                   g_param_spec_uint64 ("device-detection-time",
 
883
                                                        NULL,
 
884
                                                        NULL,
 
885
                                                        0,
 
886
                                                        G_MAXUINT64,
 
887
                                                        0,
 
888
                                                        G_PARAM_READABLE));
 
889
  g_object_class_install_property (object_class,
 
890
                                   PROP_DEVICE_MEDIA_DETECTION_TIME,
 
891
                                   g_param_spec_uint64 ("device-media-detection-time",
 
892
                                                        NULL,
 
893
                                                        NULL,
 
894
                                                        0,
 
895
                                                        G_MAXUINT64,
 
896
                                                        0,
 
897
                                                        G_PARAM_READABLE));
 
898
  g_object_class_install_property (object_class, PROP_DEVICE_MAJOR, g_param_spec_int64 ("device-major",
 
899
                                                                                        NULL,
 
900
                                                                                        NULL,
 
901
                                                                                        -G_MAXINT64,
 
902
                                                                                        G_MAXINT64,
 
903
                                                                                        0,
 
904
                                                                                        G_PARAM_READABLE));
 
905
  g_object_class_install_property (object_class, PROP_DEVICE_MINOR, g_param_spec_int64 ("device-minor",
 
906
                                                                                        NULL,
 
907
                                                                                        NULL,
 
908
                                                                                        -G_MAXINT64,
 
909
                                                                                        G_MAXINT64,
 
910
                                                                                        0,
 
911
                                                                                        G_PARAM_READABLE));
 
912
  g_object_class_install_property (object_class,
 
913
                                   PROP_DEVICE_FILE,
 
914
                                   g_param_spec_string ("device-file",
 
915
                                                        NULL,
 
916
                                                        NULL,
 
917
                                                        NULL,
 
918
                                                        G_PARAM_READABLE));
 
919
  g_object_class_install_property (object_class,
 
920
                                   PROP_DEVICE_FILE_PRESENTATION,
 
921
                                   g_param_spec_string ("device-file-presentation",
 
922
                                                        NULL,
 
923
                                                        NULL,
 
924
                                                        NULL,
 
925
                                                        G_PARAM_READABLE));
 
926
  g_object_class_install_property (object_class,
 
927
                                   PROP_DEVICE_FILE_BY_ID,
 
928
                                   g_param_spec_boxed ("device-file-by-id",
 
929
                                                       NULL,
 
930
                                                       NULL,
 
931
                                                       dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING),
 
932
                                                       G_PARAM_READABLE));
 
933
  g_object_class_install_property (object_class,
 
934
                                   PROP_DEVICE_FILE_BY_PATH,
 
935
                                   g_param_spec_boxed ("device-file-by-path",
 
936
                                                       NULL,
 
937
                                                       NULL,
 
938
                                                       dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING),
 
939
                                                       G_PARAM_READABLE));
 
940
  g_object_class_install_property (object_class,
 
941
                                   PROP_DEVICE_IS_SYSTEM_INTERNAL,
 
942
                                   g_param_spec_boolean ("device-is-system-internal",
 
943
                                                         NULL,
 
944
                                                         NULL,
 
945
                                                         FALSE,
 
946
                                                         G_PARAM_READABLE));
 
947
  g_object_class_install_property (object_class, PROP_DEVICE_IS_PARTITION, g_param_spec_boolean ("device-is-partition",
 
948
                                                                                                 NULL,
 
949
                                                                                                 NULL,
 
950
                                                                                                 FALSE,
 
951
                                                                                                 G_PARAM_READABLE));
 
952
  g_object_class_install_property (object_class,
 
953
                                   PROP_DEVICE_IS_PARTITION_TABLE,
 
954
                                   g_param_spec_boolean ("device-is-partition-table",
 
955
                                                         NULL,
 
956
                                                         NULL,
 
957
                                                         FALSE,
 
958
                                                         G_PARAM_READABLE));
 
959
  g_object_class_install_property (object_class, PROP_DEVICE_IS_REMOVABLE, g_param_spec_boolean ("device-is-removable",
 
960
                                                                                                 NULL,
 
961
                                                                                                 NULL,
 
962
                                                                                                 FALSE,
 
963
                                                                                                 G_PARAM_READABLE));
 
964
  g_object_class_install_property (object_class,
 
965
                                   PROP_DEVICE_IS_MEDIA_AVAILABLE,
 
966
                                   g_param_spec_boolean ("device-is-media-available",
 
967
                                                         NULL,
 
968
                                                         NULL,
 
969
                                                         FALSE,
 
970
                                                         G_PARAM_READABLE));
 
971
  g_object_class_install_property (object_class,
 
972
                                   PROP_DEVICE_IS_MEDIA_CHANGE_DETECTED,
 
973
                                   g_param_spec_boolean ("device-is-media-change-detected",
 
974
                                                         NULL,
 
975
                                                         NULL,
 
976
                                                         FALSE,
 
977
                                                         G_PARAM_READABLE));
 
978
  g_object_class_install_property (object_class,
 
979
                                   PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_POLLING,
 
980
                                   g_param_spec_boolean ("device-is-media-change-detection-polling",
 
981
                                                         NULL,
 
982
                                                         NULL,
 
983
                                                         FALSE,
 
984
                                                         G_PARAM_READABLE));
 
985
  g_object_class_install_property (object_class,
 
986
                                   PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_INHIBITABLE,
 
987
                                   g_param_spec_boolean ("device-is-media-change-detection-inhibitable",
 
988
                                                         NULL,
 
989
                                                         NULL,
 
990
                                                         FALSE,
 
991
                                                         G_PARAM_READABLE));
 
992
  g_object_class_install_property (object_class,
 
993
                                   PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_INHIBITED,
 
994
                                   g_param_spec_boolean ("device-is-media-change-detection-inhibited",
 
995
                                                         NULL,
 
996
                                                         NULL,
 
997
                                                         FALSE,
 
998
                                                         G_PARAM_READABLE));
 
999
  g_object_class_install_property (object_class, PROP_DEVICE_IS_READ_ONLY, g_param_spec_boolean ("device-is-read-only",
 
1000
                                                                                                 NULL,
 
1001
                                                                                                 NULL,
 
1002
                                                                                                 FALSE,
 
1003
                                                                                                 G_PARAM_READABLE));
 
1004
  g_object_class_install_property (object_class, PROP_DEVICE_IS_DRIVE, g_param_spec_boolean ("device-is-drive",
 
1005
                                                                                             NULL,
 
1006
                                                                                             NULL,
 
1007
                                                                                             FALSE,
 
1008
                                                                                             G_PARAM_READABLE));
 
1009
  g_object_class_install_property (object_class,
 
1010
                                   PROP_DEVICE_IS_OPTICAL_DISC,
 
1011
                                   g_param_spec_boolean ("device-is-optical-disc", NULL, NULL, FALSE, G_PARAM_READABLE));
 
1012
  g_object_class_install_property (object_class, PROP_DEVICE_IS_LUKS, g_param_spec_boolean ("device-is-luks",
 
1013
                                                                                            NULL,
 
1014
                                                                                            NULL,
 
1015
                                                                                            FALSE,
 
1016
                                                                                            G_PARAM_READABLE));
 
1017
  g_object_class_install_property (object_class,
 
1018
                                   PROP_DEVICE_IS_LUKS_CLEARTEXT,
 
1019
                                   g_param_spec_boolean ("device-is-luks-cleartext",
 
1020
                                                         NULL,
 
1021
                                                         NULL,
 
1022
                                                         FALSE,
 
1023
                                                         G_PARAM_READABLE));
 
1024
  g_object_class_install_property (object_class,
 
1025
                                   PROP_DEVICE_IS_LINUX_MD_COMPONENT,
 
1026
                                   g_param_spec_boolean ("device-is-linux-md-component",
 
1027
                                                         NULL,
 
1028
                                                         NULL,
 
1029
                                                         FALSE,
 
1030
                                                         G_PARAM_READABLE));
 
1031
  g_object_class_install_property (object_class, PROP_DEVICE_IS_LINUX_MD, g_param_spec_boolean ("device-is-linux-md",
 
1032
                                                                                                NULL,
 
1033
                                                                                                NULL,
 
1034
                                                                                                FALSE,
 
1035
                                                                                                G_PARAM_READABLE));
 
1036
  g_object_class_install_property (object_class,
 
1037
                                   PROP_DEVICE_IS_LINUX_LVM2_LV,
 
1038
                                   g_param_spec_boolean ("device-is-linux-lvm2-lv",
 
1039
                                                         NULL,
 
1040
                                                         NULL,
 
1041
                                                         FALSE,
 
1042
                                                         G_PARAM_READABLE));
 
1043
  g_object_class_install_property (object_class,
 
1044
                                   PROP_DEVICE_IS_LINUX_LVM2_PV,
 
1045
                                   g_param_spec_boolean ("device-is-linux-lvm2-pv",
 
1046
                                                         NULL,
 
1047
                                                         NULL,
 
1048
                                                         FALSE,
 
1049
                                                         G_PARAM_READABLE));
 
1050
  g_object_class_install_property (object_class,
 
1051
                                   PROP_DEVICE_IS_LINUX_DMMP,
 
1052
                                   g_param_spec_boolean ("device-is-linux-dmmp",
 
1053
                                                         NULL,
 
1054
                                                         NULL,
 
1055
                                                         FALSE,
 
1056
                                                         G_PARAM_READABLE));
 
1057
  g_object_class_install_property (object_class,
 
1058
                                   PROP_DEVICE_IS_LINUX_DMMP_COMPONENT,
 
1059
                                   g_param_spec_boolean ("device-is-linux-dmmp-component",
 
1060
                                                         NULL,
 
1061
                                                         NULL,
 
1062
                                                         FALSE,
 
1063
                                                         G_PARAM_READABLE));
 
1064
  g_object_class_install_property (object_class,
 
1065
                                   PROP_DEVICE_IS_LINUX_LOOP,
 
1066
                                   g_param_spec_boolean ("device-is-linux-loop",
 
1067
                                                         NULL,
 
1068
                                                         NULL,
 
1069
                                                         FALSE,
 
1070
                                                         G_PARAM_READABLE));
 
1071
 
 
1072
  g_object_class_install_property (object_class, PROP_DEVICE_SIZE, g_param_spec_uint64 ("device-size",
 
1073
                                                                                        NULL,
 
1074
                                                                                        NULL,
 
1075
                                                                                        0,
 
1076
                                                                                        G_MAXUINT64,
 
1077
                                                                                        0,
 
1078
                                                                                        G_PARAM_READABLE));
 
1079
  g_object_class_install_property (object_class, PROP_DEVICE_BLOCK_SIZE, g_param_spec_uint64 ("device-block-size",
 
1080
                                                                                              NULL,
 
1081
                                                                                              NULL,
 
1082
                                                                                              0,
 
1083
                                                                                              G_MAXUINT64,
 
1084
                                                                                              0,
 
1085
                                                                                              G_PARAM_READABLE));
 
1086
  g_object_class_install_property (object_class, PROP_DEVICE_IS_MOUNTED, g_param_spec_boolean ("device-is-mounted",
 
1087
                                                                                               NULL,
 
1088
                                                                                               NULL,
 
1089
                                                                                               FALSE,
 
1090
                                                                                               G_PARAM_READABLE));
 
1091
  g_object_class_install_property (object_class,
 
1092
                                   PROP_DEVICE_MOUNT_PATHS,
 
1093
                                   g_param_spec_boxed ("device-mount-paths",
 
1094
                                                       NULL,
 
1095
                                                       NULL,
 
1096
                                                       dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING),
 
1097
                                                       G_PARAM_READABLE));
 
1098
  g_object_class_install_property (object_class,
 
1099
                                   PROP_DEVICE_MOUNTED_BY_UID,
 
1100
                                   g_param_spec_uint ("device-mounted-by-uid",
 
1101
                                                      NULL,
 
1102
                                                      NULL,
 
1103
                                                      0,
 
1104
                                                      G_MAXUINT,
 
1105
                                                      0,
 
1106
                                                      G_PARAM_READABLE));
 
1107
  g_object_class_install_property (object_class,
 
1108
                                   PROP_DEVICE_PRESENTATION_HIDE,
 
1109
                                   g_param_spec_boolean ("device-presentation-hide",
 
1110
                                                         NULL,
 
1111
                                                         NULL,
 
1112
                                                         FALSE,
 
1113
                                                         G_PARAM_READABLE));
 
1114
  g_object_class_install_property (object_class,
 
1115
                                   PROP_DEVICE_PRESENTATION_NOPOLICY,
 
1116
                                   g_param_spec_boolean ("device-presentation-nopolicy",
 
1117
                                                         NULL,
 
1118
                                                         NULL,
 
1119
                                                         FALSE,
 
1120
                                                         G_PARAM_READABLE));
 
1121
  g_object_class_install_property (object_class,
 
1122
                                   PROP_DEVICE_PRESENTATION_NAME,
 
1123
                                   g_param_spec_string ("device-presentation-name", NULL, NULL, NULL, G_PARAM_READABLE));
 
1124
  g_object_class_install_property (object_class,
 
1125
                                   PROP_DEVICE_PRESENTATION_ICON_NAME,
 
1126
                                   g_param_spec_string ("device-presentation-icon-name",
 
1127
                                                        NULL,
 
1128
                                                        NULL,
 
1129
                                                        NULL,
 
1130
                                                        G_PARAM_READABLE));
 
1131
 
 
1132
  g_object_class_install_property (object_class, PROP_JOB_IN_PROGRESS, g_param_spec_boolean ("job-in-progress",
 
1133
                                                                                             NULL,
 
1134
                                                                                             NULL,
 
1135
                                                                                             FALSE,
 
1136
                                                                                             G_PARAM_READABLE));
 
1137
  g_object_class_install_property (object_class, PROP_JOB_ID, g_param_spec_string ("job-id",
 
1138
                                                                                   NULL,
 
1139
                                                                                   NULL,
 
1140
                                                                                   NULL,
 
1141
                                                                                   G_PARAM_READABLE));
 
1142
  g_object_class_install_property (object_class, PROP_JOB_INITIATED_BY_UID, g_param_spec_uint ("job-initiated-by-uid",
 
1143
                                                                                               NULL,
 
1144
                                                                                               NULL,
 
1145
                                                                                               0,
 
1146
                                                                                               G_MAXUINT,
 
1147
                                                                                               0,
 
1148
                                                                                               G_PARAM_READABLE));
 
1149
  g_object_class_install_property (object_class, PROP_JOB_IS_CANCELLABLE, g_param_spec_boolean ("job-is-cancellable",
 
1150
                                                                                                NULL,
 
1151
                                                                                                NULL,
 
1152
                                                                                                FALSE,
 
1153
                                                                                                G_PARAM_READABLE));
 
1154
  g_object_class_install_property (object_class, PROP_JOB_PERCENTAGE, g_param_spec_double ("job-percentage",
 
1155
                                                                                           NULL,
 
1156
                                                                                           NULL,
 
1157
                                                                                           -1,
 
1158
                                                                                           100,
 
1159
                                                                                           -1,
 
1160
                                                                                           G_PARAM_READABLE));
 
1161
 
 
1162
  g_object_class_install_property (object_class, PROP_ID_USAGE, g_param_spec_string ("id-usage",
 
1163
                                                                                     NULL,
 
1164
                                                                                     NULL,
 
1165
                                                                                     NULL,
 
1166
                                                                                     G_PARAM_READABLE));
 
1167
  g_object_class_install_property (object_class, PROP_ID_TYPE, g_param_spec_string ("id-type",
 
1168
                                                                                    NULL,
 
1169
                                                                                    NULL,
 
1170
                                                                                    NULL,
 
1171
                                                                                    G_PARAM_READABLE));
 
1172
  g_object_class_install_property (object_class, PROP_ID_VERSION, g_param_spec_string ("id-version",
 
1173
                                                                                       NULL,
 
1174
                                                                                       NULL,
 
1175
                                                                                       NULL,
 
1176
                                                                                       G_PARAM_READABLE));
 
1177
  g_object_class_install_property (object_class, PROP_ID_UUID, g_param_spec_string ("id-uuid",
 
1178
                                                                                    NULL,
 
1179
                                                                                    NULL,
 
1180
                                                                                    NULL,
 
1181
                                                                                    G_PARAM_READABLE));
 
1182
  g_object_class_install_property (object_class, PROP_ID_LABEL, g_param_spec_string ("id-label",
 
1183
                                                                                     NULL,
 
1184
                                                                                     NULL,
 
1185
                                                                                     NULL,
 
1186
                                                                                     G_PARAM_READABLE));
 
1187
 
 
1188
  g_object_class_install_property (object_class, PROP_PARTITION_SLAVE, g_param_spec_boxed ("partition-slave",
 
1189
                                                                                           NULL,
 
1190
                                                                                           NULL,
 
1191
                                                                                           DBUS_TYPE_G_OBJECT_PATH,
 
1192
                                                                                           G_PARAM_READABLE));
 
1193
  g_object_class_install_property (object_class, PROP_PARTITION_SCHEME, g_param_spec_string ("partition-scheme",
 
1194
                                                                                             NULL,
 
1195
                                                                                             NULL,
 
1196
                                                                                             NULL,
 
1197
                                                                                             G_PARAM_READABLE));
 
1198
  g_object_class_install_property (object_class, PROP_PARTITION_TYPE, g_param_spec_string ("partition-type",
 
1199
                                                                                           NULL,
 
1200
                                                                                           NULL,
 
1201
                                                                                           NULL,
 
1202
                                                                                           G_PARAM_READABLE));
 
1203
  g_object_class_install_property (object_class, PROP_PARTITION_LABEL, g_param_spec_string ("partition-label",
 
1204
                                                                                            NULL,
 
1205
                                                                                            NULL,
 
1206
                                                                                            NULL,
 
1207
                                                                                            G_PARAM_READABLE));
 
1208
  g_object_class_install_property (object_class, PROP_PARTITION_UUID, g_param_spec_string ("partition-uuid",
 
1209
                                                                                           NULL,
 
1210
                                                                                           NULL,
 
1211
                                                                                           NULL,
 
1212
                                                                                           G_PARAM_READABLE));
 
1213
  g_object_class_install_property (object_class,
 
1214
                                   PROP_PARTITION_FLAGS,
 
1215
                                   g_param_spec_boxed ("partition-flags",
 
1216
                                                       NULL,
 
1217
                                                       NULL,
 
1218
                                                       dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING),
 
1219
                                                       G_PARAM_READABLE));
 
1220
  g_object_class_install_property (object_class, PROP_PARTITION_NUMBER, g_param_spec_int ("partition-number",
 
1221
                                                                                          NULL,
 
1222
                                                                                          NULL,
 
1223
                                                                                          0,
 
1224
                                                                                          G_MAXINT,
 
1225
                                                                                          0,
 
1226
                                                                                          G_PARAM_READABLE));
 
1227
  g_object_class_install_property (object_class, PROP_PARTITION_OFFSET, g_param_spec_uint64 ("partition-offset",
 
1228
                                                                                             NULL,
 
1229
                                                                                             NULL,
 
1230
                                                                                             0,
 
1231
                                                                                             G_MAXUINT64,
 
1232
                                                                                             0,
 
1233
                                                                                             G_PARAM_READABLE));
 
1234
  g_object_class_install_property (object_class, PROP_PARTITION_SIZE, g_param_spec_uint64 ("partition-size",
 
1235
                                                                                           NULL,
 
1236
                                                                                           NULL,
 
1237
                                                                                           0,
 
1238
                                                                                           G_MAXUINT64,
 
1239
                                                                                           0,
 
1240
                                                                                           G_PARAM_READABLE));
 
1241
  g_object_class_install_property (object_class,
 
1242
                                   PROP_PARTITION_ALIGNMENT_OFFSET,
 
1243
                                   g_param_spec_uint64 ("partition-alignment-offset",
 
1244
                                                        NULL,
 
1245
                                                        NULL,
 
1246
                                                        0,
 
1247
                                                        G_MAXUINT64,
 
1248
                                                        0,
 
1249
                                                        G_PARAM_READABLE));
 
1250
 
 
1251
  g_object_class_install_property (object_class,
 
1252
                                   PROP_PARTITION_TABLE_SCHEME,
 
1253
                                   g_param_spec_string ("partition-table-scheme", NULL, NULL, NULL, G_PARAM_READABLE));
 
1254
  g_object_class_install_property (object_class, PROP_PARTITION_TABLE_COUNT, g_param_spec_int ("partition-table-count",
 
1255
                                                                                               NULL,
 
1256
                                                                                               NULL,
 
1257
                                                                                               0,
 
1258
                                                                                               G_MAXINT,
 
1259
                                                                                               0,
 
1260
                                                                                               G_PARAM_READABLE));
 
1261
 
 
1262
  g_object_class_install_property (object_class, PROP_LUKS_HOLDER, g_param_spec_boxed ("luks-holder",
 
1263
                                                                                       NULL,
 
1264
                                                                                       NULL,
 
1265
                                                                                       DBUS_TYPE_G_OBJECT_PATH,
 
1266
                                                                                       G_PARAM_READABLE));
 
1267
 
 
1268
  g_object_class_install_property (object_class,
 
1269
                                   PROP_LUKS_CLEARTEXT_SLAVE,
 
1270
                                   g_param_spec_boxed ("luks-cleartext-slave",
 
1271
                                                       NULL,
 
1272
                                                       NULL,
 
1273
                                                       DBUS_TYPE_G_OBJECT_PATH,
 
1274
                                                       G_PARAM_READABLE));
 
1275
  g_object_class_install_property (object_class,
 
1276
                                   PROP_LUKS_CLEARTEXT_UNLOCKED_BY_UID,
 
1277
                                   g_param_spec_uint ("luks-cleartext-unlocked-by-uid",
 
1278
                                                      NULL,
 
1279
                                                      NULL,
 
1280
                                                      0,
 
1281
                                                      G_MAXUINT,
 
1282
                                                      0,
 
1283
                                                      G_PARAM_READABLE));
 
1284
 
 
1285
  g_object_class_install_property (object_class, PROP_DRIVE_VENDOR, g_param_spec_string ("drive-vendor",
 
1286
                                                                                         NULL,
 
1287
                                                                                         NULL,
 
1288
                                                                                         NULL,
 
1289
                                                                                         G_PARAM_READABLE));
 
1290
  g_object_class_install_property (object_class, PROP_DRIVE_MODEL, g_param_spec_string ("drive-model",
 
1291
                                                                                        NULL,
 
1292
                                                                                        NULL,
 
1293
                                                                                        NULL,
 
1294
                                                                                        G_PARAM_READABLE));
 
1295
  g_object_class_install_property (object_class, PROP_DRIVE_REVISION, g_param_spec_string ("drive-revision",
 
1296
                                                                                           NULL,
 
1297
                                                                                           NULL,
 
1298
                                                                                           NULL,
 
1299
                                                                                           G_PARAM_READABLE));
 
1300
  g_object_class_install_property (object_class, PROP_DRIVE_SERIAL, g_param_spec_string ("drive-serial",
 
1301
                                                                                         NULL,
 
1302
                                                                                         NULL,
 
1303
                                                                                         NULL,
 
1304
                                                                                         G_PARAM_READABLE));
 
1305
  g_object_class_install_property (object_class, PROP_DRIVE_WWN, g_param_spec_string ("drive-wwn",
 
1306
                                                                                      NULL,
 
1307
                                                                                      NULL,
 
1308
                                                                                      NULL,
 
1309
                                                                                      G_PARAM_READABLE));
 
1310
  g_object_class_install_property (object_class,
 
1311
                                   PROP_DRIVE_CONNECTION_INTERFACE,
 
1312
                                   g_param_spec_string ("drive-connection-interface",
 
1313
                                                        NULL,
 
1314
                                                        NULL,
 
1315
                                                        NULL,
 
1316
                                                        G_PARAM_READABLE));
 
1317
  g_object_class_install_property (object_class,
 
1318
                                   PROP_DRIVE_CONNECTION_SPEED,
 
1319
                                   g_param_spec_uint64 ("drive-connection-speed",
 
1320
                                                        NULL,
 
1321
                                                        NULL,
 
1322
                                                        0,
 
1323
                                                        G_MAXUINT64,
 
1324
                                                        0,
 
1325
                                                        G_PARAM_READABLE));
 
1326
  g_object_class_install_property (object_class,
 
1327
                                   PROP_DRIVE_MEDIA_COMPATIBILITY,
 
1328
                                   g_param_spec_boxed ("drive-media-compatibility",
 
1329
                                                       NULL,
 
1330
                                                       NULL,
 
1331
                                                       dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING),
 
1332
                                                       G_PARAM_READABLE));
 
1333
  g_object_class_install_property (object_class, PROP_DRIVE_MEDIA, g_param_spec_string ("drive-media",
 
1334
                                                                                        NULL,
 
1335
                                                                                        NULL,
 
1336
                                                                                        NULL,
 
1337
                                                                                        G_PARAM_READABLE));
 
1338
  g_object_class_install_property (object_class,
 
1339
                                   PROP_DRIVE_IS_MEDIA_EJECTABLE,
 
1340
                                   g_param_spec_boolean ("drive-is-media-ejectable",
 
1341
                                                         NULL,
 
1342
                                                         NULL,
 
1343
                                                         FALSE,
 
1344
                                                         G_PARAM_READABLE));
 
1345
  g_object_class_install_property (object_class, PROP_DRIVE_CAN_DETACH, g_param_spec_boolean ("drive-can-detach",
 
1346
                                                                                              NULL,
 
1347
                                                                                              NULL,
 
1348
                                                                                              FALSE,
 
1349
                                                                                              G_PARAM_READABLE));
 
1350
  g_object_class_install_property (object_class, PROP_DRIVE_CAN_SPINDOWN, g_param_spec_boolean ("drive-can-spindown",
 
1351
                                                                                                NULL,
 
1352
                                                                                                NULL,
 
1353
                                                                                                FALSE,
 
1354
                                                                                                G_PARAM_READABLE));
 
1355
  g_object_class_install_property (object_class, PROP_DRIVE_IS_ROTATIONAL, g_param_spec_boolean ("drive-is-rotational",
 
1356
                                                                                                 NULL,
 
1357
                                                                                                 NULL,
 
1358
                                                                                                 FALSE,
 
1359
                                                                                                 G_PARAM_READABLE));
 
1360
  g_object_class_install_property (object_class, PROP_DRIVE_ROTATION_RATE, g_param_spec_uint ("drive-rotation-rate",
 
1361
                                                                                              NULL,
 
1362
                                                                                              NULL,
 
1363
                                                                                              0,
 
1364
                                                                                              G_MAXUINT,
 
1365
                                                                                              0,
 
1366
                                                                                              G_PARAM_READABLE));
 
1367
  g_object_class_install_property (object_class, PROP_DRIVE_WRITE_CACHE, g_param_spec_string ("drive-write-cache",
 
1368
                                                                                              NULL,
 
1369
                                                                                              NULL,
 
1370
                                                                                              FALSE,
 
1371
                                                                                              G_PARAM_READABLE));
 
1372
  g_object_class_install_property (object_class, PROP_DRIVE_ADAPTER, g_param_spec_boxed ("drive-adapter",
 
1373
                                                                                         NULL,
 
1374
                                                                                         NULL,
 
1375
                                                                                         DBUS_TYPE_G_OBJECT_PATH,
 
1376
                                                                                         G_PARAM_READABLE));
 
1377
  g_object_class_install_property (object_class,
 
1378
                                   PROP_DRIVE_PORTS,
 
1379
                                   g_param_spec_boxed ("drive-ports",
 
1380
                                                       NULL,
 
1381
                                                       NULL,
 
1382
                                                       dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH),
 
1383
                                                       G_PARAM_READABLE));
 
1384
  g_object_class_install_property (object_class,
 
1385
                                   PROP_DRIVE_SIMILAR_DEVICES,
 
1386
                                   g_param_spec_boxed ("drive-similar-devices",
 
1387
                                                       NULL,
 
1388
                                                       NULL,
 
1389
                                                       dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH),
 
1390
                                                       G_PARAM_READABLE));
 
1391
 
 
1392
  g_object_class_install_property (object_class,
 
1393
                                   PROP_OPTICAL_DISC_IS_BLANK,
 
1394
                                   g_param_spec_boolean ("optical-disc-is-blank", NULL, NULL, FALSE, G_PARAM_READABLE));
 
1395
  g_object_class_install_property (object_class,
 
1396
                                   PROP_OPTICAL_DISC_IS_APPENDABLE,
 
1397
                                   g_param_spec_boolean ("optical-disc-is-appendable",
 
1398
                                                         NULL,
 
1399
                                                         NULL,
 
1400
                                                         FALSE,
 
1401
                                                         G_PARAM_READABLE));
 
1402
  g_object_class_install_property (object_class,
 
1403
                                   PROP_OPTICAL_DISC_IS_CLOSED,
 
1404
                                   g_param_spec_boolean ("optical-disc-is-closed", NULL, NULL, FALSE, G_PARAM_READABLE));
 
1405
  g_object_class_install_property (object_class,
 
1406
                                   PROP_OPTICAL_DISC_NUM_TRACKS,
 
1407
                                   g_param_spec_uint ("optical-disc-num-tracks",
 
1408
                                                      NULL,
 
1409
                                                      NULL,
 
1410
                                                      0,
 
1411
                                                      G_MAXUINT,
 
1412
                                                      0,
 
1413
                                                      G_PARAM_READABLE));
 
1414
  g_object_class_install_property (object_class,
 
1415
                                   PROP_OPTICAL_DISC_NUM_AUDIO_TRACKS,
 
1416
                                   g_param_spec_uint ("optical-disc-num-audio-tracks",
 
1417
                                                      NULL,
 
1418
                                                      NULL,
 
1419
                                                      0,
 
1420
                                                      G_MAXUINT,
 
1421
                                                      0,
 
1422
                                                      G_PARAM_READABLE));
 
1423
  g_object_class_install_property (object_class,
 
1424
                                   PROP_OPTICAL_DISC_NUM_SESSIONS,
 
1425
                                   g_param_spec_uint ("optical-disc-num-sessions",
 
1426
                                                      NULL,
 
1427
                                                      NULL,
 
1428
                                                      0,
 
1429
                                                      G_MAXUINT,
 
1430
                                                      0,
 
1431
                                                      G_PARAM_READABLE));
 
1432
 
 
1433
  g_object_class_install_property (object_class,
 
1434
                                   PROP_DRIVE_ATA_SMART_IS_AVAILABLE,
 
1435
                                   g_param_spec_boolean ("drive-ata-smart-is-available",
 
1436
                                                         NULL,
 
1437
                                                         NULL,
 
1438
                                                         FALSE,
 
1439
                                                         G_PARAM_READABLE));
 
1440
  g_object_class_install_property (object_class,
 
1441
                                   PROP_DRIVE_ATA_SMART_TIME_COLLECTED,
 
1442
                                   g_param_spec_uint64 ("drive-ata-smart-time-collected",
 
1443
                                                        NULL,
 
1444
                                                        NULL,
 
1445
                                                        0,
 
1446
                                                        G_MAXUINT64,
 
1447
                                                        0,
 
1448
                                                        G_PARAM_READABLE));
 
1449
  g_object_class_install_property (object_class,
 
1450
                                   PROP_DRIVE_ATA_SMART_STATUS,
 
1451
                                   g_param_spec_string ("drive-ata-smart-status", NULL, NULL, NULL, G_PARAM_READABLE));
 
1452
  g_object_class_install_property (object_class,
 
1453
                                   PROP_DRIVE_ATA_SMART_BLOB,
 
1454
                                   g_param_spec_boxed ("drive-ata-smart-blob",
 
1455
                                                       NULL,
 
1456
                                                       NULL,
 
1457
                                                       dbus_g_type_get_collection ("GArray", G_TYPE_UCHAR),
 
1458
                                                       G_PARAM_READABLE));
 
1459
 
 
1460
  g_object_class_install_property (object_class,
 
1461
                                   PROP_LINUX_MD_COMPONENT_LEVEL,
 
1462
                                   g_param_spec_string ("linux-md-component-level", NULL, NULL, NULL, G_PARAM_READABLE));
 
1463
  g_object_class_install_property (object_class,
 
1464
                                   PROP_LINUX_MD_COMPONENT_POSITION,
 
1465
                                   g_param_spec_int ("linux-md-component-position",
 
1466
                                                     NULL,
 
1467
                                                     NULL,
 
1468
                                                     0,
 
1469
                                                     G_MAXINT,
 
1470
                                                     0,
 
1471
                                                     G_PARAM_READABLE));
 
1472
  g_object_class_install_property (object_class,
 
1473
                                   PROP_LINUX_MD_COMPONENT_NUM_RAID_DEVICES,
 
1474
                                   g_param_spec_int ("linux-md-component-num-raid-devices",
 
1475
                                                     NULL,
 
1476
                                                     NULL,
 
1477
                                                     0,
 
1478
                                                     G_MAXINT,
 
1479
                                                     0,
 
1480
                                                     G_PARAM_READABLE));
 
1481
  g_object_class_install_property (object_class,
 
1482
                                   PROP_LINUX_MD_COMPONENT_UUID,
 
1483
                                   g_param_spec_string ("linux-md-component-uuid", NULL, NULL, NULL, G_PARAM_READABLE));
 
1484
  g_object_class_install_property (object_class,
 
1485
                                   PROP_LINUX_MD_COMPONENT_HOME_HOST,
 
1486
                                   g_param_spec_string ("linux-md-component-home-host",
 
1487
                                                        NULL,
 
1488
                                                        NULL,
 
1489
                                                        NULL,
 
1490
                                                        G_PARAM_READABLE));
 
1491
  g_object_class_install_property (object_class,
 
1492
                                   PROP_LINUX_MD_COMPONENT_NAME,
 
1493
                                   g_param_spec_string ("linux-md-component-name", NULL, NULL, NULL, G_PARAM_READABLE));
 
1494
  g_object_class_install_property (object_class,
 
1495
                                   PROP_LINUX_MD_COMPONENT_VERSION,
 
1496
                                   g_param_spec_string ("linux-md-component-version",
 
1497
                                                        NULL,
 
1498
                                                        NULL,
 
1499
                                                        NULL,
 
1500
                                                        G_PARAM_READABLE));
 
1501
  g_object_class_install_property (object_class,
 
1502
                                   PROP_LINUX_MD_COMPONENT_HOLDER,
 
1503
                                   g_param_spec_boxed ("linux-md-component-holder",
 
1504
                                                       NULL,
 
1505
                                                       NULL,
 
1506
                                                       DBUS_TYPE_G_OBJECT_PATH,
 
1507
                                                       G_PARAM_READABLE));
 
1508
  g_object_class_install_property (object_class,
 
1509
                                   PROP_LINUX_MD_COMPONENT_STATE,
 
1510
                                   g_param_spec_boxed ("linux-md-component-state",
 
1511
                                                       NULL,
 
1512
                                                       NULL,
 
1513
                                                       dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING),
 
1514
                                                       G_PARAM_READABLE));
 
1515
 
 
1516
  g_object_class_install_property (object_class, PROP_LINUX_MD_STATE, g_param_spec_string ("linux-md-state",
 
1517
                                                                                           NULL,
 
1518
                                                                                           NULL,
 
1519
                                                                                           NULL,
 
1520
                                                                                           G_PARAM_READABLE));
 
1521
  g_object_class_install_property (object_class, PROP_LINUX_MD_LEVEL, g_param_spec_string ("linux-md-level",
 
1522
                                                                                           NULL,
 
1523
                                                                                           NULL,
 
1524
                                                                                           NULL,
 
1525
                                                                                           G_PARAM_READABLE));
 
1526
  g_object_class_install_property (object_class,
 
1527
                                   PROP_LINUX_MD_NUM_RAID_DEVICES,
 
1528
                                   g_param_spec_int ("linux-md-num-raid-devices",
 
1529
                                                     NULL,
 
1530
                                                     NULL,
 
1531
                                                     0,
 
1532
                                                     G_MAXINT,
 
1533
                                                     0,
 
1534
                                                     G_PARAM_READABLE));
 
1535
  g_object_class_install_property (object_class, PROP_LINUX_MD_UUID, g_param_spec_string ("linux-md-uuid",
 
1536
                                                                                          NULL,
 
1537
                                                                                          NULL,
 
1538
                                                                                          NULL,
 
1539
                                                                                          G_PARAM_READABLE));
 
1540
  g_object_class_install_property (object_class, PROP_LINUX_MD_HOME_HOST, g_param_spec_string ("linux-md-home-host",
 
1541
                                                                                               NULL,
 
1542
                                                                                               NULL,
 
1543
                                                                                               NULL,
 
1544
                                                                                               G_PARAM_READABLE));
 
1545
  g_object_class_install_property (object_class, PROP_LINUX_MD_NAME, g_param_spec_string ("linux-md-name",
 
1546
                                                                                          NULL,
 
1547
                                                                                          NULL,
 
1548
                                                                                          NULL,
 
1549
                                                                                          G_PARAM_READABLE));
 
1550
  g_object_class_install_property (object_class, PROP_LINUX_MD_VERSION, g_param_spec_string ("linux-md-version",
 
1551
                                                                                             NULL,
 
1552
                                                                                             NULL,
 
1553
                                                                                             NULL,
 
1554
                                                                                             G_PARAM_READABLE));
 
1555
  g_object_class_install_property (object_class,
 
1556
                                   PROP_LINUX_MD_SLAVES,
 
1557
                                   g_param_spec_boxed ("linux-md-slaves",
 
1558
                                                       NULL,
 
1559
                                                       NULL,
 
1560
                                                       dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH),
 
1561
                                                       G_PARAM_READABLE));
 
1562
  g_object_class_install_property (object_class,
 
1563
                                   PROP_LINUX_MD_IS_DEGRADED,
 
1564
                                   g_param_spec_boolean ("linux-md-is-degraded", NULL, NULL, FALSE, G_PARAM_READABLE));
 
1565
  g_object_class_install_property (object_class,
 
1566
                                   PROP_LINUX_MD_SYNC_ACTION,
 
1567
                                   g_param_spec_string ("linux-md-sync-action", NULL, NULL, NULL, G_PARAM_READABLE));
 
1568
  g_object_class_install_property (object_class,
 
1569
                                   PROP_LINUX_MD_SYNC_PERCENTAGE,
 
1570
                                   g_param_spec_double ("linux-md-sync-percentage",
 
1571
                                                        NULL,
 
1572
                                                        NULL,
 
1573
                                                        0.0,
 
1574
                                                        100.0,
 
1575
                                                        0.0,
 
1576
                                                        G_PARAM_READABLE));
 
1577
  g_object_class_install_property (object_class, PROP_LINUX_MD_SYNC_SPEED, g_param_spec_uint64 ("linux-md-sync-speed",
 
1578
                                                                                                NULL,
 
1579
                                                                                                NULL,
 
1580
                                                                                                0,
 
1581
                                                                                                G_MAXUINT64,
 
1582
                                                                                                0,
 
1583
                                                                                                G_PARAM_READABLE));
 
1584
 
 
1585
  g_object_class_install_property (object_class,
 
1586
                                   PROP_LINUX_LVM2_LV_NAME,
 
1587
                                   g_param_spec_string ("linux-lvm2-lv-name",
 
1588
                                                        NULL,
 
1589
                                                        NULL,
 
1590
                                                        NULL,
 
1591
                                                        G_PARAM_READABLE));
 
1592
  g_object_class_install_property (object_class,
 
1593
                                   PROP_LINUX_LVM2_LV_UUID,
 
1594
                                   g_param_spec_string ("linux-lvm2-lv-uuid",
 
1595
                                                        NULL,
 
1596
                                                        NULL,
 
1597
                                                        NULL,
 
1598
                                                        G_PARAM_READABLE));
 
1599
  g_object_class_install_property (object_class,
 
1600
                                   PROP_LINUX_LVM2_LV_GROUP_NAME,
 
1601
                                   g_param_spec_string ("linux-lvm2-lv-group-name",
 
1602
                                                        NULL,
 
1603
                                                        NULL,
 
1604
                                                        NULL,
 
1605
                                                        G_PARAM_READABLE));
 
1606
  g_object_class_install_property (object_class,
 
1607
                                   PROP_LINUX_LVM2_LV_GROUP_UUID,
 
1608
                                   g_param_spec_string ("linux-lvm2-lv-group-uuid",
 
1609
                                                        NULL,
 
1610
                                                        NULL,
 
1611
                                                        NULL,
 
1612
                                                        G_PARAM_READABLE));
 
1613
 
 
1614
  g_object_class_install_property (object_class,
 
1615
                                   PROP_LINUX_LVM2_PV_UUID,
 
1616
                                   g_param_spec_string ("linux-lvm2-pv-uuid",
 
1617
                                                        NULL,
 
1618
                                                        NULL,
 
1619
                                                        NULL,
 
1620
                                                        G_PARAM_READABLE));
 
1621
  g_object_class_install_property (object_class,
 
1622
                                   PROP_LINUX_LVM2_PV_NUM_METADATA_AREAS,
 
1623
                                   g_param_spec_uint ("linux-lvm2-pv-num-metadata-areas",
 
1624
                                                      NULL,
 
1625
                                                      NULL,
 
1626
                                                      0,
 
1627
                                                      G_MAXUINT,
 
1628
                                                      0,
 
1629
                                                      G_PARAM_READABLE));
 
1630
  g_object_class_install_property (object_class,
 
1631
                                   PROP_LINUX_LVM2_PV_GROUP_NAME,
 
1632
                                   g_param_spec_string ("linux-lvm2-pv-group-name",
 
1633
                                                        NULL,
 
1634
                                                        NULL,
 
1635
                                                        NULL,
 
1636
                                                        G_PARAM_READABLE));
 
1637
  g_object_class_install_property (object_class,
 
1638
                                   PROP_LINUX_LVM2_PV_GROUP_UUID,
 
1639
                                   g_param_spec_string ("linux-lvm2-pv-group-uuid",
 
1640
                                                        NULL,
 
1641
                                                        NULL,
 
1642
                                                        NULL,
 
1643
                                                        G_PARAM_READABLE));
 
1644
  g_object_class_install_property (object_class,
 
1645
                                   PROP_LINUX_LVM2_PV_GROUP_SIZE,
 
1646
                                   g_param_spec_uint64 ("linux-lvm2-pv-group-size",
 
1647
                                                        NULL,
 
1648
                                                        NULL,
 
1649
                                                        0,
 
1650
                                                        G_MAXUINT64,
 
1651
                                                        0,
 
1652
                                                        G_PARAM_READABLE));
 
1653
  g_object_class_install_property (object_class,
 
1654
                                   PROP_LINUX_LVM2_PV_GROUP_UNALLOCATED_SIZE,
 
1655
                                   g_param_spec_uint64 ("linux-lvm2-pv-group-unallocated-size",
 
1656
                                                        NULL,
 
1657
                                                        NULL,
 
1658
                                                        0,
 
1659
                                                        G_MAXUINT64,
 
1660
                                                        0,
 
1661
                                                        G_PARAM_READABLE));
 
1662
  g_object_class_install_property (object_class,
 
1663
                                   PROP_LINUX_LVM2_PV_GROUP_SEQUENCE_NUMBER,
 
1664
                                   g_param_spec_uint64 ("linux-lvm2-pv-group-sequence-number",
 
1665
                                                        NULL,
 
1666
                                                        NULL,
 
1667
                                                        0,
 
1668
                                                        G_MAXUINT64,
 
1669
                                                        0,
 
1670
                                                        G_PARAM_READABLE));
 
1671
  g_object_class_install_property (object_class,
 
1672
                                   PROP_LINUX_LVM2_PV_GROUP_EXTENT_SIZE,
 
1673
                                   g_param_spec_uint64 ("linux-lvm2-pv-group-extent-size",
 
1674
                                                        NULL,
 
1675
                                                        NULL,
 
1676
                                                        0,
 
1677
                                                        G_MAXUINT64,
 
1678
                                                        0,
 
1679
                                                        G_PARAM_READABLE));
 
1680
  g_object_class_install_property (object_class,
 
1681
                                   PROP_LINUX_LVM2_PV_GROUP_PHYSICAL_VOLUMES,
 
1682
                                   g_param_spec_boxed ("linux-lvm2-pv-group-physical-volumes",
 
1683
                                                       NULL,
 
1684
                                                       NULL,
 
1685
                                                       dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING),
 
1686
                                                       G_PARAM_READABLE));
 
1687
  g_object_class_install_property (object_class,
 
1688
                                   PROP_LINUX_LVM2_PV_GROUP_LOGICAL_VOLUMES,
 
1689
                                   g_param_spec_boxed ("linux-lvm2-pv-group-logical-volumes",
 
1690
                                                       NULL,
 
1691
                                                       NULL,
 
1692
                                                       dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING),
 
1693
                                                       G_PARAM_READABLE));
 
1694
  g_object_class_install_property (object_class,
 
1695
                                   PROP_LINUX_DMMP_COMPONENT_HOLDER,
 
1696
                                   g_param_spec_boxed ("linux-dmmp-component-holder",
 
1697
                                                       NULL,
 
1698
                                                       NULL,
 
1699
                                                       DBUS_TYPE_G_OBJECT_PATH,
 
1700
                                                       G_PARAM_READABLE));
 
1701
 
 
1702
  g_object_class_install_property (object_class,
 
1703
                                   PROP_LINUX_DMMP_NAME,
 
1704
                                   g_param_spec_string ("linux-dmmp-name",
 
1705
                                                        NULL,
 
1706
                                                        NULL,
 
1707
                                                        NULL,
 
1708
                                                        G_PARAM_READABLE));
 
1709
  g_object_class_install_property (object_class,
 
1710
                                   PROP_LINUX_DMMP_PARAMETERS,
 
1711
                                   g_param_spec_string ("linux-dmmp-parameters",
 
1712
                                                        NULL,
 
1713
                                                        NULL,
 
1714
                                                        NULL,
 
1715
                                                        G_PARAM_READABLE));
 
1716
  g_object_class_install_property (object_class,
 
1717
                                   PROP_LINUX_DMMP_SLAVES,
 
1718
                                   g_param_spec_boxed ("linux-dmmp-slaves",
 
1719
                                                       NULL,
 
1720
                                                       NULL,
 
1721
                                                       dbus_g_type_get_collection ("GPtrArray",
 
1722
                                                                                   DBUS_TYPE_G_OBJECT_PATH),
 
1723
                                                       G_PARAM_READABLE));
 
1724
 
 
1725
  g_object_class_install_property (object_class,
 
1726
                                   PROP_LINUX_LOOP_FILENAME,
 
1727
                                   g_param_spec_string ("linux-loop-filename",
 
1728
                                                        NULL,
 
1729
                                                        NULL,
 
1730
                                                        NULL,
 
1731
                                                        G_PARAM_READABLE));
 
1732
}
 
1733
 
 
1734
static void
 
1735
device_init (Device *device)
 
1736
{
 
1737
  device->priv = DEVICE_GET_PRIVATE (device);
 
1738
 
 
1739
  device->priv->device_file_by_id = g_ptr_array_new ();
 
1740
  device->priv->device_file_by_path = g_ptr_array_new ();
 
1741
  device->priv->device_mount_paths = g_ptr_array_new ();
 
1742
  device->priv->partition_flags = g_ptr_array_new ();
 
1743
  device->priv->drive_media_compatibility = g_ptr_array_new ();
 
1744
  device->priv->drive_ports = g_ptr_array_new ();
 
1745
  device->priv->drive_similar_devices = g_ptr_array_new ();
 
1746
  device->priv->linux_md_component_state = g_ptr_array_new ();
 
1747
  device->priv->linux_md_slaves = g_ptr_array_new ();
 
1748
  device->priv->linux_lvm2_pv_group_physical_volumes = g_ptr_array_new ();
 
1749
  device->priv->linux_lvm2_pv_group_logical_volumes = g_ptr_array_new ();
 
1750
  device->priv->linux_dmmp_slaves = g_ptr_array_new ();
 
1751
 
 
1752
  device->priv->slaves_objpath = g_ptr_array_new ();
 
1753
  device->priv->holders_objpath = g_ptr_array_new ();
 
1754
 
 
1755
  device->priv->drive_ata_smart_status = -1;
 
1756
}
 
1757
 
 
1758
static void
 
1759
device_finalize (GObject *object)
 
1760
{
 
1761
  Device *device;
 
1762
  GList *l;
 
1763
 
 
1764
  g_return_if_fail (object != NULL);
 
1765
  g_return_if_fail (IS_DEVICE (object));
 
1766
 
 
1767
  device = DEVICE (object);
 
1768
  g_return_if_fail (device->priv != NULL);
 
1769
 
 
1770
  /* g_debug ("finalizing %s", device->priv->native_path); */
 
1771
 
 
1772
  g_object_unref (device->priv->d);
 
1773
  g_object_unref (device->priv->daemon);
 
1774
  g_free (device->priv->object_path);
 
1775
 
 
1776
  g_free (device->priv->native_path);
 
1777
 
 
1778
  for (l = device->priv->polling_inhibitors; l != NULL; l = l->next)
 
1779
    {
 
1780
      Inhibitor *inhibitor = INHIBITOR (l->data);
 
1781
      g_signal_handlers_disconnect_by_func (inhibitor, polling_inhibitor_disconnected_cb, device);
 
1782
      g_object_unref (inhibitor);
 
1783
    }
 
1784
  g_list_free (device->priv->polling_inhibitors);
 
1785
 
 
1786
  for (l = device->priv->spindown_inhibitors; l != NULL; l = l->next)
 
1787
    {
 
1788
      Inhibitor *inhibitor = INHIBITOR (l->data);
 
1789
      g_signal_handlers_disconnect_by_func (inhibitor, spindown_inhibitor_disconnected_cb, device);
 
1790
      g_object_unref (inhibitor);
 
1791
    }
 
1792
  g_list_free (device->priv->spindown_inhibitors);
 
1793
 
 
1794
  if (device->priv->linux_md_poll_timeout_id > 0)
 
1795
    g_source_remove (device->priv->linux_md_poll_timeout_id);
 
1796
 
 
1797
  if (device->priv->emit_changed_idle_id > 0)
 
1798
    g_source_remove (device->priv->emit_changed_idle_id);
 
1799
 
 
1800
  /* free properties */
 
1801
  g_free (device->priv->device_file);
 
1802
  g_free (device->priv->device_file_presentation);
 
1803
  g_ptr_array_foreach (device->priv->device_file_by_id, (GFunc) g_free, NULL);
 
1804
  g_ptr_array_foreach (device->priv->device_file_by_path, (GFunc) g_free, NULL);
 
1805
  g_ptr_array_free (device->priv->device_file_by_id, TRUE);
 
1806
  g_ptr_array_free (device->priv->device_file_by_path, TRUE);
 
1807
  g_ptr_array_free (device->priv->device_mount_paths, TRUE);
 
1808
  g_free (device->priv->device_presentation_name);
 
1809
  g_free (device->priv->device_presentation_icon_name);
 
1810
 
 
1811
  g_free (device->priv->id_usage);
 
1812
  g_free (device->priv->id_type);
 
1813
  g_free (device->priv->id_version);
 
1814
  g_free (device->priv->id_uuid);
 
1815
  g_free (device->priv->id_label);
 
1816
 
 
1817
  g_free (device->priv->partition_slave);
 
1818
  g_free (device->priv->partition_scheme);
 
1819
  g_free (device->priv->partition_type);
 
1820
  g_free (device->priv->partition_label);
 
1821
  g_free (device->priv->partition_uuid);
 
1822
  g_ptr_array_foreach (device->priv->partition_flags, (GFunc) g_free, NULL);
 
1823
  g_ptr_array_free (device->priv->partition_flags, TRUE);
 
1824
 
 
1825
  g_free (device->priv->partition_table_scheme);
 
1826
 
 
1827
  g_free (device->priv->luks_holder);
 
1828
 
 
1829
  g_free (device->priv->luks_cleartext_slave);
 
1830
 
 
1831
  g_free (device->priv->drive_vendor);
 
1832
  g_free (device->priv->drive_model);
 
1833
  g_free (device->priv->drive_revision);
 
1834
  g_free (device->priv->drive_serial);
 
1835
  g_free (device->priv->drive_wwn);
 
1836
  g_free (device->priv->drive_connection_interface);
 
1837
  g_ptr_array_foreach (device->priv->drive_media_compatibility, (GFunc) g_free, NULL);
 
1838
  g_ptr_array_free (device->priv->drive_media_compatibility, TRUE);
 
1839
  g_free (device->priv->drive_media);
 
1840
  g_free (device->priv->drive_write_cache);
 
1841
  g_free (device->priv->drive_adapter);
 
1842
  g_ptr_array_foreach (device->priv->drive_ports, (GFunc) g_free, NULL);
 
1843
  g_ptr_array_free (device->priv->drive_ports, TRUE);
 
1844
  g_ptr_array_foreach (device->priv->drive_similar_devices, (GFunc) g_free, NULL);
 
1845
  g_ptr_array_free (device->priv->drive_similar_devices, TRUE);
 
1846
 
 
1847
  g_free (device->priv->linux_md_component_level);
 
1848
  g_free (device->priv->linux_md_component_uuid);
 
1849
  g_free (device->priv->linux_md_component_home_host);
 
1850
  g_free (device->priv->linux_md_component_name);
 
1851
  g_free (device->priv->linux_md_component_version);
 
1852
  g_free (device->priv->linux_md_component_holder);
 
1853
  g_ptr_array_foreach (device->priv->linux_md_component_state, (GFunc) g_free, NULL);
 
1854
  g_ptr_array_free (device->priv->linux_md_component_state, TRUE);
 
1855
 
 
1856
  g_free (device->priv->linux_md_state);
 
1857
  g_free (device->priv->linux_md_level);
 
1858
  g_free (device->priv->linux_md_uuid);
 
1859
  g_free (device->priv->linux_md_home_host);
 
1860
  g_free (device->priv->linux_md_name);
 
1861
  g_free (device->priv->linux_md_version);
 
1862
  g_ptr_array_foreach (device->priv->linux_md_slaves, (GFunc) g_free, NULL);
 
1863
  g_ptr_array_free (device->priv->linux_md_slaves, TRUE);
 
1864
 
 
1865
  g_free (device->priv->linux_dmmp_component_holder);
 
1866
 
 
1867
  g_free (device->priv->linux_dmmp_name);
 
1868
  g_ptr_array_foreach (device->priv->linux_dmmp_slaves, (GFunc) g_free, NULL);
 
1869
  g_ptr_array_free (device->priv->linux_dmmp_slaves, TRUE);
 
1870
  g_free (device->priv->linux_dmmp_parameters);
 
1871
 
 
1872
  g_free (device->priv->linux_loop_filename);
 
1873
 
 
1874
  g_free (device->priv->linux_lvm2_lv_name);
 
1875
  g_free (device->priv->linux_lvm2_lv_uuid);
 
1876
  g_free (device->priv->linux_lvm2_lv_group_name);
 
1877
  g_free (device->priv->linux_lvm2_lv_group_uuid);
 
1878
 
 
1879
  g_free (device->priv->linux_lvm2_pv_uuid);
 
1880
  g_free (device->priv->linux_lvm2_pv_group_name);
 
1881
  g_free (device->priv->linux_lvm2_pv_group_uuid);
 
1882
  g_ptr_array_foreach (device->priv->linux_lvm2_pv_group_physical_volumes, (GFunc) g_free, NULL);
 
1883
  g_ptr_array_free (device->priv->linux_lvm2_pv_group_physical_volumes, TRUE);
 
1884
  g_ptr_array_foreach (device->priv->linux_lvm2_pv_group_logical_volumes, (GFunc) g_free, NULL);
 
1885
  g_ptr_array_free (device->priv->linux_lvm2_pv_group_logical_volumes, TRUE);
 
1886
 
 
1887
  g_free (device->priv->drive_ata_smart_blob);
 
1888
 
 
1889
  g_free (device->priv->dm_name);
 
1890
  g_ptr_array_foreach (device->priv->slaves_objpath, (GFunc) g_free, NULL);
 
1891
  g_ptr_array_free (device->priv->slaves_objpath, TRUE);
 
1892
  g_ptr_array_foreach (device->priv->holders_objpath, (GFunc) g_free, NULL);
 
1893
  g_ptr_array_free (device->priv->holders_objpath, TRUE);
 
1894
 
 
1895
  G_OBJECT_CLASS (device_parent_class)->finalize (object);
 
1896
}
 
1897
 
 
1898
/**
 
1899
 * compute_object_path:
 
1900
 * @native_path: Either an absolute sysfs path or the basename
 
1901
 *
 
1902
 * Maps @native_path to the D-Bus object path for the device.
 
1903
 *
 
1904
 * Returns: A valid D-Bus object path. Free with g_free().
 
1905
 */
 
1906
static char *
 
1907
compute_object_path (const char *native_path)
 
1908
{
 
1909
  const gchar *basename;
 
1910
  GString *s;
 
1911
  guint n;
 
1912
 
 
1913
  g_return_val_if_fail (native_path != NULL, NULL);
 
1914
 
 
1915
  basename = strrchr (native_path, '/');
 
1916
  if (basename != NULL)
 
1917
    {
 
1918
      basename++;
 
1919
    }
 
1920
  else
 
1921
    {
 
1922
      basename = native_path;
 
1923
    }
 
1924
 
 
1925
  s = g_string_new ("/org/freedesktop/UDisks/devices/");
 
1926
  for (n = 0; basename[n] != '\0'; n++)
 
1927
    {
 
1928
      gint c = basename[n];
 
1929
 
 
1930
      /* D-Bus spec sez:
 
1931
       *
 
1932
       * Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_"
 
1933
       */
 
1934
      if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'))
 
1935
        {
 
1936
          g_string_append_c (s, c);
 
1937
        }
 
1938
      else
 
1939
        {
 
1940
          /* Escape bytes not in [A-Z][a-z][0-9] as _<hex-with-two-digits> */
 
1941
          g_string_append_printf (s, "_%02x", c);
 
1942
        }
 
1943
    }
 
1944
 
 
1945
  return g_string_free (s, FALSE);
 
1946
}
 
1947
 
 
1948
static gboolean
 
1949
register_disks_device (Device *device)
 
1950
{
 
1951
  GError *error = NULL;
 
1952
 
 
1953
  device->priv->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
 
1954
  if (device->priv->system_bus_connection == NULL)
 
1955
    {
 
1956
      if (error != NULL)
 
1957
        {
 
1958
          g_critical ("error getting system bus: %s", error->message);
 
1959
          g_error_free (error);
 
1960
        }
 
1961
      goto error;
 
1962
    }
 
1963
  device->priv->object_path = compute_object_path (device->priv->native_path);
 
1964
 
 
1965
  /* safety first */
 
1966
  if (dbus_g_connection_lookup_g_object (device->priv->system_bus_connection, device->priv->object_path) != NULL)
 
1967
    {
 
1968
      g_error ("**** HACK: Wanting to register object at path `%s' but there is already an "
 
1969
               "object there. This is an internal error in the daemon. Aborting.\n", device->priv->object_path);
 
1970
    }
 
1971
 
 
1972
  dbus_g_connection_register_g_object (device->priv->system_bus_connection,
 
1973
                                       device->priv->object_path,
 
1974
                                       G_OBJECT (device));
 
1975
 
 
1976
  return TRUE;
 
1977
 
 
1978
 error:
 
1979
  return FALSE;
 
1980
}
 
1981
 
 
1982
static double
 
1983
sysfs_get_double (const char *dir,
 
1984
                  const char *attribute)
 
1985
{
 
1986
  double result;
 
1987
  char *contents;
 
1988
  char *filename;
 
1989
 
 
1990
  result = 0.0;
 
1991
  filename = g_build_filename (dir, attribute, NULL);
 
1992
  if (g_file_get_contents (filename, &contents, NULL, NULL))
 
1993
    {
 
1994
      result = atof (contents);
 
1995
      g_free (contents);
 
1996
    }
 
1997
  g_free (filename);
 
1998
 
 
1999
  return result;
 
2000
}
 
2001
 
 
2002
static char *
 
2003
sysfs_get_string (const char *dir,
 
2004
                  const char *attribute)
 
2005
{
 
2006
  char *result;
 
2007
  char *filename;
 
2008
 
 
2009
  result = NULL;
 
2010
  filename = g_build_filename (dir, attribute, NULL);
 
2011
  if (!g_file_get_contents (filename, &result, NULL, NULL))
 
2012
    {
 
2013
      result = g_strdup ("");
 
2014
    }
 
2015
  g_free (filename);
 
2016
 
 
2017
  return result;
 
2018
}
 
2019
 
 
2020
static int
 
2021
sysfs_get_int (const char *dir,
 
2022
               const char *attribute)
 
2023
{
 
2024
  int result;
 
2025
  char *contents;
 
2026
  char *filename;
 
2027
 
 
2028
  result = 0;
 
2029
  filename = g_build_filename (dir, attribute, NULL);
 
2030
  if (g_file_get_contents (filename, &contents, NULL, NULL))
 
2031
    {
 
2032
      result = strtol (contents, NULL, 0);
 
2033
      g_free (contents);
 
2034
    }
 
2035
  g_free (filename);
 
2036
 
 
2037
  return result;
 
2038
}
 
2039
 
 
2040
static guint64
 
2041
sysfs_get_uint64 (const char *dir,
 
2042
                  const char *attribute)
 
2043
{
 
2044
  guint64 result;
 
2045
  char *contents;
 
2046
  char *filename;
 
2047
 
 
2048
  result = 0;
 
2049
  filename = g_build_filename (dir, attribute, NULL);
 
2050
  if (g_file_get_contents (filename, &contents, NULL, NULL))
 
2051
    {
 
2052
      result = strtoll (contents, NULL, 0);
 
2053
      g_free (contents);
 
2054
    }
 
2055
  g_free (filename);
 
2056
 
 
2057
  return result;
 
2058
}
 
2059
 
 
2060
static gboolean
 
2061
sysfs_file_exists (const char *dir,
 
2062
                   const char *attribute)
 
2063
{
 
2064
  gboolean result;
 
2065
  char *filename;
 
2066
 
 
2067
  result = FALSE;
 
2068
  filename = g_build_filename (dir, attribute, NULL);
 
2069
  if (g_file_test (filename, G_FILE_TEST_EXISTS))
 
2070
    {
 
2071
      result = TRUE;
 
2072
    }
 
2073
  g_free (filename);
 
2074
 
 
2075
  return result;
 
2076
}
 
2077
 
 
2078
static void
 
2079
device_generate_kernel_change_event (Device *device)
 
2080
{
 
2081
  FILE *f;
 
2082
  char *filename;
 
2083
 
 
2084
  filename = g_build_filename (device->priv->native_path, "uevent", NULL);
 
2085
  f = fopen (filename, "w");
 
2086
  if (f == NULL)
 
2087
    {
 
2088
      g_warning ("error opening %s for writing: %m", filename);
 
2089
    }
 
2090
  else
 
2091
    {
 
2092
      if (fputs ("change", f) == EOF)
 
2093
        {
 
2094
          g_warning ("error writing 'change' to %s: %m", filename);
 
2095
        }
 
2096
      fclose (f);
 
2097
    }
 
2098
  g_free (filename);
 
2099
}
 
2100
 
 
2101
static char *
 
2102
_dupv8 (const char *s)
 
2103
{
 
2104
  const char *end_valid;
 
2105
 
 
2106
  if (!g_utf8_validate (s, -1, &end_valid))
 
2107
    {
 
2108
      g_print ("**** NOTE: The string '%s' is not valid UTF-8. Invalid characters begins at '%s'\n", s, end_valid);
 
2109
      return g_strndup (s, end_valid - s);
 
2110
    }
 
2111
  else
 
2112
    {
 
2113
      return g_strdup (s);
 
2114
    }
 
2115
}
 
2116
 
 
2117
static char *
 
2118
sysfs_resolve_link (const char *sysfs_path,
 
2119
                    const char *name)
 
2120
{
 
2121
  char *full_path;
 
2122
  char link_path[PATH_MAX];
 
2123
  char resolved_path[PATH_MAX];
 
2124
  ssize_t num;
 
2125
  gboolean found_it;
 
2126
 
 
2127
  found_it = FALSE;
 
2128
 
 
2129
  full_path = g_build_filename (sysfs_path, name, NULL);
 
2130
 
 
2131
  //g_debug ("name='%s'", name);
 
2132
  //g_debug ("full_path='%s'", full_path);
 
2133
  num = readlink (full_path, link_path, sizeof(link_path) - 1);
 
2134
  if (num != -1)
 
2135
    {
 
2136
      char *absolute_path;
 
2137
 
 
2138
      link_path[num] = '\0';
 
2139
 
 
2140
      //g_debug ("link_path='%s'", link_path);
 
2141
      absolute_path = g_build_filename (sysfs_path, link_path, NULL);
 
2142
      //g_debug ("absolute_path='%s'", absolute_path);
 
2143
      if (realpath (absolute_path, resolved_path) != NULL)
 
2144
        {
 
2145
          //g_debug ("resolved_path='%s'", resolved_path);
 
2146
          found_it = TRUE;
 
2147
        }
 
2148
      g_free (absolute_path);
 
2149
    }
 
2150
  g_free (full_path);
 
2151
 
 
2152
  if (found_it)
 
2153
    return g_strdup (resolved_path);
 
2154
  else
 
2155
    return NULL;
 
2156
}
 
2157
 
 
2158
/* unescapes things like \x20 to " " and ensures the returned string is valid UTF-8.
 
2159
 *
 
2160
 * see volume_id_encode_string() in extras/volume_id/lib/volume_id.c in the
 
2161
 * udev tree for the encoder
 
2162
 */
 
2163
static gchar *
 
2164
decode_udev_encoded_string (const gchar *str)
 
2165
{
 
2166
  GString *s;
 
2167
  gchar *ret;
 
2168
  const gchar *end_valid;
 
2169
  guint n;
 
2170
 
 
2171
  s = g_string_new (NULL);
 
2172
  for (n = 0; str[n] != '\0'; n++)
 
2173
    {
 
2174
      if (str[n] == '\\')
 
2175
        {
 
2176
          gint val;
 
2177
 
 
2178
          if (str[n + 1] != 'x' || str[n + 2] == '\0' || str[n + 3] == '\0')
 
2179
            {
 
2180
              g_print ("**** NOTE: malformed encoded string '%s'\n", str);
 
2181
              break;
 
2182
            }
 
2183
 
 
2184
          val = (g_ascii_xdigit_value (str[n + 2]) << 4) | g_ascii_xdigit_value (str[n + 3]);
 
2185
 
 
2186
          g_string_append_c (s, val);
 
2187
 
 
2188
          n += 3;
 
2189
        }
 
2190
      else
 
2191
        {
 
2192
          g_string_append_c (s, str[n]);
 
2193
        }
 
2194
    }
 
2195
 
 
2196
  if (!g_utf8_validate (s->str, -1, &end_valid))
 
2197
    {
 
2198
      g_print ("**** NOTE: The string '%s' is not valid UTF-8. Invalid characters begins at '%s'\n", s->str, end_valid);
 
2199
      ret = g_strndup (s->str, end_valid - s->str);
 
2200
      g_string_free (s, TRUE);
 
2201
    }
 
2202
  else
 
2203
    {
 
2204
      ret = g_string_free (s, FALSE);
 
2205
    }
 
2206
 
 
2207
  return ret;
 
2208
}
 
2209
 
 
2210
static gboolean
 
2211
poll_syncing_md_device (gpointer user_data)
 
2212
{
 
2213
  Device *device = DEVICE (user_data);
 
2214
 
 
2215
  g_print ("**** POLL SYNCING MD %s\n", device->priv->native_path);
 
2216
 
 
2217
  device->priv->linux_md_poll_timeout_id = 0;
 
2218
  daemon_local_synthesize_changed (device->priv->daemon, device);
 
2219
  return FALSE;
 
2220
}
 
2221
 
 
2222
static GList *
 
2223
dup_list_from_ptrarray (GPtrArray *p)
 
2224
{
 
2225
  GList *ret;
 
2226
  guint n;
 
2227
 
 
2228
  ret = NULL;
 
2229
 
 
2230
  for (n = 0; n < p->len; n++)
 
2231
    ret = g_list_prepend (ret, g_strdup (((gchar **) p->pdata)[n]));
 
2232
 
 
2233
  return ret;
 
2234
}
 
2235
 
 
2236
static gint
 
2237
ptr_str_array_compare (const gchar **a,
 
2238
                       const gchar **b)
 
2239
{
 
2240
  return g_strcmp0 (*a, *b);
 
2241
}
 
2242
 
 
2243
static void
 
2244
diff_sorted_lists (GList *list1,
 
2245
                   GList *list2,
 
2246
                   GCompareFunc compare,
 
2247
                   GList **added,
 
2248
                   GList **removed)
 
2249
{
 
2250
  int order;
 
2251
 
 
2252
  *added = *removed = NULL;
 
2253
 
 
2254
  while (list1 != NULL && list2 != NULL)
 
2255
    {
 
2256
      order = (*compare) (list1->data, list2->data);
 
2257
      if (order < 0)
 
2258
        {
 
2259
          *removed = g_list_prepend (*removed, list1->data);
 
2260
          list1 = list1->next;
 
2261
        }
 
2262
      else if (order > 0)
 
2263
        {
 
2264
          *added = g_list_prepend (*added, list2->data);
 
2265
          list2 = list2->next;
 
2266
        }
 
2267
      else
 
2268
        { /* same item */
 
2269
          list1 = list1->next;
 
2270
          list2 = list2->next;
 
2271
        }
 
2272
    }
 
2273
 
 
2274
  while (list1 != NULL)
 
2275
    {
 
2276
      *removed = g_list_prepend (*removed, list1->data);
 
2277
      list1 = list1->next;
 
2278
    }
 
2279
  while (list2 != NULL)
 
2280
    {
 
2281
      *added = g_list_prepend (*added, list2->data);
 
2282
      list2 = list2->next;
 
2283
    }
 
2284
}
 
2285
 
 
2286
/* ---------------------------------------------------------------------------------------------------- */
 
2287
 
 
2288
/* update id_* properties */
 
2289
static gboolean
 
2290
update_info_presentation (Device *device)
 
2291
{
 
2292
  gboolean hide;
 
2293
  gboolean nopolicy;
 
2294
  const gchar *automount_hint;
 
2295
 
 
2296
  hide = FALSE;
 
2297
  if (g_udev_device_has_property (device->priv->d, "UDISKS_PRESENTATION_HIDE"))
 
2298
    hide = g_udev_device_get_property_as_boolean (device->priv->d, "UDISKS_PRESENTATION_HIDE");
 
2299
  device_set_device_presentation_hide (device, hide);
 
2300
 
 
2301
  nopolicy = FALSE;
 
2302
  if (g_udev_device_has_property (device->priv->d, "UDISKS_PRESENTATION_NOPOLICY"))
 
2303
    nopolicy = g_udev_device_get_property_as_boolean (device->priv->d, "UDISKS_PRESENTATION_NOPOLICY");
 
2304
  device_set_device_presentation_nopolicy (device, nopolicy);
 
2305
 
 
2306
  device_set_device_presentation_name (device, g_udev_device_get_property (device->priv->d, "UDISKS_PRESENTATION_NAME"));
 
2307
 
 
2308
  device_set_device_presentation_icon_name (device, g_udev_device_get_property (device->priv->d,
 
2309
                                                                                "UDISKS_PRESENTATION_ICON_NAME"));
 
2310
 
 
2311
  automount_hint = "";
 
2312
  if (g_udev_device_has_property (device->priv->d, "UDISKS_AUTOMOUNT_HINT"))
 
2313
    automount_hint = g_udev_device_get_property (device->priv->d, "UDISKS_AUTOMOUNT_HINT");
 
2314
 
 
2315
  device_set_device_automount_hint (device, automount_hint);
 
2316
 
 
2317
  return TRUE;
 
2318
}
 
2319
 
 
2320
/* ---------------------------------------------------------------------------------------------------- */
 
2321
 
 
2322
/* update id_* properties */
 
2323
static gboolean
 
2324
update_info_id (Device *device)
 
2325
{
 
2326
  gchar *decoded_string;
 
2327
  const gchar *partition_scheme;
 
2328
  gint partition_type;
 
2329
 
 
2330
  partition_scheme = g_udev_device_get_property (device->priv->d, "UDISKS_PARTITION_SCHEME");
 
2331
  partition_type = g_udev_device_get_property_as_int (device->priv->d, "UDISKS_PARTITION_TYPE");
 
2332
  if (g_strcmp0 (partition_scheme, "mbr") == 0 && (partition_type == 0x05 || partition_type == 0x0f || partition_type
 
2333
                                                   == 0x85))
 
2334
    {
 
2335
      device_set_id_usage (device, "");
 
2336
      device_set_id_type (device, "");
 
2337
      device_set_id_version (device, "");
 
2338
      device_set_id_label (device, "");
 
2339
      device_set_id_uuid (device, "");
 
2340
      goto out;
 
2341
    }
 
2342
 
 
2343
  device_set_id_usage (device, g_udev_device_get_property (device->priv->d, "ID_FS_USAGE"));
 
2344
  device_set_id_type (device, g_udev_device_get_property (device->priv->d, "ID_FS_TYPE"));
 
2345
  device_set_id_version (device, g_udev_device_get_property (device->priv->d, "ID_FS_VERSION"));
 
2346
  if (g_udev_device_has_property (device->priv->d, "ID_FS_LABEL_ENC"))
 
2347
    {
 
2348
      decoded_string = decode_udev_encoded_string (g_udev_device_get_property (device->priv->d, "ID_FS_LABEL_ENC"));
 
2349
      device_set_id_label (device, decoded_string);
 
2350
      g_free (decoded_string);
 
2351
    }
 
2352
  else
 
2353
    {
 
2354
      device_set_id_label (device, g_udev_device_get_property (device->priv->d, "ID_FS_LABEL"));
 
2355
    }
 
2356
  device_set_id_uuid (device, g_udev_device_get_property (device->priv->d, "ID_FS_UUID"));
 
2357
 
 
2358
 out:
 
2359
  return TRUE;
 
2360
}
 
2361
 
 
2362
/* ---------------------------------------------------------------------------------------------------- */
 
2363
 
 
2364
/* update partition_table_* properties */
 
2365
static gboolean
 
2366
update_info_partition_table (Device *device)
 
2367
{
 
2368
  gboolean is_partition_table;
 
2369
 
 
2370
  is_partition_table = FALSE;
 
2371
 
 
2372
  /* Check if udisks-part-id identified the device as a partition table.. this includes
 
2373
   * identifying partition tables set up by kpartx for multipath etc.
 
2374
   */
 
2375
  if (g_udev_device_get_property_as_boolean (device->priv->d, "UDISKS_PARTITION_TABLE"))
 
2376
    {
 
2377
      device_set_partition_table_scheme (device,
 
2378
                                         g_udev_device_get_property (device->priv->d,
 
2379
                                                                     "UDISKS_PARTITION_TABLE_SCHEME"));
 
2380
      device_set_partition_table_count (device,
 
2381
                                        g_udev_device_get_property_as_int (device->priv->d,
 
2382
                                                                           "UDISKS_PARTITION_TABLE_COUNT"));
 
2383
      is_partition_table = TRUE;
 
2384
    }
 
2385
 
 
2386
  /* Note that udisks-part-id might not detect all partition table
 
2387
   * formats.. so in the negative case, also double check with
 
2388
   * information in sysfs.
 
2389
   *
 
2390
   * The kernel guarantees that all childs are created before the
 
2391
   * uevent for the parent is created. So if we have childs, we must
 
2392
   * be a partition table.
 
2393
   *
 
2394
   * To detect a child we check for the existance of a subdir that has
 
2395
   * the parents name as a prefix (e.g. for parent sda then sda1,
 
2396
   * sda2, sda3 ditto md0, md0p1 etc. etc. will work).
 
2397
   */
 
2398
  if (!is_partition_table)
 
2399
    {
 
2400
      gchar *s;
 
2401
      GDir *dir;
 
2402
 
 
2403
      s = g_path_get_basename (device->priv->native_path);
 
2404
      if ((dir = g_dir_open (device->priv->native_path, 0, NULL)) != NULL)
 
2405
        {
 
2406
          guint partition_count;
 
2407
          const gchar *name;
 
2408
 
 
2409
          partition_count = 0;
 
2410
          while ((name = g_dir_read_name (dir)) != NULL)
 
2411
            {
 
2412
              if (g_str_has_prefix (name, s))
 
2413
                {
 
2414
                  partition_count++;
 
2415
                }
 
2416
            }
 
2417
          g_dir_close (dir);
 
2418
 
 
2419
          if (partition_count > 0)
 
2420
            {
 
2421
              device_set_partition_table_scheme (device, "");
 
2422
              device_set_partition_table_count (device, partition_count);
 
2423
              is_partition_table = TRUE;
 
2424
            }
 
2425
        }
 
2426
      g_free (s);
 
2427
    }
 
2428
 
 
2429
  device_set_device_is_partition_table (device, is_partition_table);
 
2430
  if (!is_partition_table)
 
2431
    {
 
2432
      /* otherwise, clear all the data */
 
2433
      device_set_partition_table_scheme (device, NULL);
 
2434
      device_set_partition_table_count (device, 0);
 
2435
    }
 
2436
 
 
2437
  return TRUE;
 
2438
}
 
2439
 
 
2440
/* ---------------------------------------------------------------------------------------------------- */
 
2441
 
 
2442
/* update partition_* properties */
 
2443
static gboolean
 
2444
update_info_partition (Device *device)
 
2445
{
 
2446
  gboolean is_partition;
 
2447
 
 
2448
  is_partition = FALSE;
 
2449
 
 
2450
  /* Check if udisks-part-id identified the device as a partition.. this includes
 
2451
   * identifying partitions set up by kpartx for multipath
 
2452
   */
 
2453
  if (g_udev_device_has_property (device->priv->d, "UDISKS_PARTITION"))
 
2454
    {
 
2455
      guint64 size;
 
2456
      const gchar *scheme;
 
2457
      const gchar *type;
 
2458
      const gchar *label;
 
2459
      const gchar *uuid;
 
2460
      const gchar* const *flags;
 
2461
      guint64 offset;
 
2462
      guint64 alignment_offset;
 
2463
      const gchar *slave_sysfs_path;
 
2464
      gint number;
 
2465
 
 
2466
      scheme = g_udev_device_get_property (device->priv->d, "UDISKS_PARTITION_SCHEME");
 
2467
      size = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_PARTITION_SIZE");
 
2468
      type = g_udev_device_get_property (device->priv->d, "UDISKS_PARTITION_TYPE");
 
2469
      label = g_udev_device_get_property (device->priv->d, "UDISKS_PARTITION_LABEL");
 
2470
      uuid = g_udev_device_get_property (device->priv->d, "UDISKS_PARTITION_UUID");
 
2471
      flags = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_PARTITION_FLAGS");
 
2472
      offset = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_PARTITION_OFFSET");
 
2473
      alignment_offset = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_PARTITION_ALIGNMENT_OFFSET");
 
2474
      number = g_udev_device_get_property_as_int (device->priv->d, "UDISKS_PARTITION_NUMBER");
 
2475
      slave_sysfs_path = g_udev_device_get_property (device->priv->d, "UDISKS_PARTITION_SLAVE");
 
2476
 
 
2477
      if (slave_sysfs_path != NULL && scheme != NULL && number > 0)
 
2478
        {
 
2479
          gchar *s;
 
2480
 
 
2481
          device_set_partition_scheme (device, scheme);
 
2482
          device_set_partition_size (device, size);
 
2483
          device_set_partition_type (device, type);
 
2484
          device_set_partition_label (device, label);
 
2485
          device_set_partition_uuid (device, uuid);
 
2486
          device_set_partition_flags (device, (gchar **) flags);
 
2487
          device_set_partition_offset (device, offset);
 
2488
          device_set_partition_alignment_offset (device, alignment_offset);
 
2489
          device_set_partition_number (device, number);
 
2490
 
 
2491
          s = compute_object_path (slave_sysfs_path);
 
2492
          device_set_partition_slave (device, s);
 
2493
          g_free (s);
 
2494
 
 
2495
          is_partition = TRUE;
 
2496
        }
 
2497
    }
 
2498
 
 
2499
  /* Also handle the case where we are partitioned by the kernel and don't have
 
2500
   * any UDISKS_PARTITION_* properties.
 
2501
   *
 
2502
   * This works without any udev UDISKS_PARTITION_* properties and is
 
2503
   * there for maximum compatibility since udisks-part-id only knows a
 
2504
   * limited set of partition table formats.
 
2505
   */
 
2506
  if (!is_partition && sysfs_file_exists (device->priv->native_path, "start"))
 
2507
    {
 
2508
      guint64 size;
 
2509
      guint64 offset;
 
2510
      guint64 alignment_offset;
 
2511
      gchar *s;
 
2512
      guint n;
 
2513
 
 
2514
      device_set_device_is_partition (device, TRUE);
 
2515
      size = sysfs_get_uint64 (device->priv->native_path, "size");
 
2516
      alignment_offset = sysfs_get_uint64 (device->priv->native_path, "alignment_offset");
 
2517
 
 
2518
      device_set_partition_size (device, size * 512); /* device->priv->device_block_size; */
 
2519
      device_set_partition_alignment_offset (device, alignment_offset);
 
2520
 
 
2521
      offset = sysfs_get_uint64 (device->priv->native_path, "start") * device->priv->device_block_size;
 
2522
      device_set_partition_offset (device, offset);
 
2523
 
 
2524
      s = device->priv->native_path;
 
2525
      for (n = strlen (s) - 1; n >= 0 && g_ascii_isdigit (s[n]); n--)
 
2526
        ;
 
2527
      device_set_partition_number (device, strtol (s + n + 1, NULL, 0));
 
2528
 
 
2529
      s = g_strdup (device->priv->native_path);
 
2530
      for (n = strlen (s) - 1; n >= 0 && s[n] != '/'; n--)
 
2531
        s[n] = '\0';
 
2532
      s[n] = '\0';
 
2533
      device_set_partition_slave (device, compute_object_path (s));
 
2534
      g_free (s);
 
2535
 
 
2536
      is_partition = TRUE;
 
2537
    }
 
2538
 
 
2539
  device_set_device_is_partition (device, is_partition);
 
2540
  if (!is_partition)
 
2541
    {
 
2542
      /* otherwise, clear all the data */
 
2543
      device_set_partition_scheme (device, NULL);
 
2544
      device_set_partition_size (device, device->priv->device_size);
 
2545
      device_set_partition_type (device, NULL);
 
2546
      device_set_partition_label (device, NULL);
 
2547
      device_set_partition_uuid (device, NULL);
 
2548
      device_set_partition_flags (device, NULL);
 
2549
    }
 
2550
  else
 
2551
    {
 
2552
      device_set_device_is_drive (device, FALSE);
 
2553
    }
 
2554
 
 
2555
  return TRUE;
 
2556
}
 
2557
 
 
2558
/* ---------------------------------------------------------------------------------------------------- */
 
2559
 
 
2560
/* this function sets
 
2561
 *
 
2562
 *  - drive_vendor (unless set already)
 
2563
 *  - drive_model (unless set already)
 
2564
 *  - connection_interface  (if we can figure that out)
 
2565
 *  - connection_speed (if we can figure that out)
 
2566
 *
 
2567
 * All this should really come from udev properties but right now it isn't.
 
2568
 */
 
2569
static void
 
2570
update_drive_properties_from_sysfs (Device *device)
 
2571
{
 
2572
  char *s;
 
2573
  char *p;
 
2574
  char *q;
 
2575
  char *model;
 
2576
  char *vendor;
 
2577
  char *subsystem;
 
2578
  char *serial;
 
2579
  char *revision;
 
2580
  const char *connection_interface;
 
2581
  guint64 connection_speed;
 
2582
 
 
2583
  connection_interface = NULL;
 
2584
  connection_speed = 0;
 
2585
 
 
2586
  /* walk up the device tree to figure out the subsystem */
 
2587
  s = g_strdup (device->priv->native_path);
 
2588
  do
 
2589
    {
 
2590
      p = sysfs_resolve_link (s, "subsystem");
 
2591
      if (p != NULL)
 
2592
        {
 
2593
          subsystem = g_path_get_basename (p);
 
2594
          g_free (p);
 
2595
 
 
2596
          if (strcmp (subsystem, "scsi") == 0)
 
2597
            {
 
2598
              connection_interface = "scsi";
 
2599
              connection_speed = 0;
 
2600
 
 
2601
              /* continue walking up the chain; we just use scsi as a fallback */
 
2602
 
 
2603
              /* grab the names from SCSI since the names from udev currently
 
2604
               *  - replaces whitespace with _
 
2605
               *  - is missing for e.g. Firewire
 
2606
               */
 
2607
              vendor = sysfs_get_string (s, "vendor");
 
2608
              if (vendor != NULL)
 
2609
                {
 
2610
                  g_strstrip (vendor);
 
2611
                  /* Don't overwrite what we set earlier from ID_VENDOR */
 
2612
                  if (device->priv->drive_vendor == NULL)
 
2613
                    {
 
2614
                      q = _dupv8 (vendor);
 
2615
                      device_set_drive_vendor (device, q);
 
2616
                      g_free (q);
 
2617
                    }
 
2618
                  g_free (vendor);
 
2619
                }
 
2620
 
 
2621
              model = sysfs_get_string (s, "model");
 
2622
              if (model != NULL)
 
2623
                {
 
2624
                  g_strstrip (model);
 
2625
                  /* Don't overwrite what we set earlier from ID_MODEL */
 
2626
                  if (device->priv->drive_model == NULL)
 
2627
                    {
 
2628
                      q = _dupv8 (model);
 
2629
                      device_set_drive_model (device, q);
 
2630
                      g_free (q);
 
2631
                    }
 
2632
                  g_free (model);
 
2633
                }
 
2634
 
 
2635
              /* TODO: need to improve this code; we probably need the kernel to export more
 
2636
               *       information before we can properly get the type and speed.
 
2637
               */
 
2638
 
 
2639
              if (device->priv->drive_vendor != NULL && strcmp (device->priv->drive_vendor, "ATA") == 0)
 
2640
                {
 
2641
                  connection_interface = "ata";
 
2642
                  break;
 
2643
                }
 
2644
 
 
2645
            }
 
2646
          else if (strcmp (subsystem, "usb") == 0)
 
2647
            {
 
2648
              double usb_speed;
 
2649
 
 
2650
              /* both the interface and the device will be 'usb'. However only
 
2651
               * the device will have the 'speed' property.
 
2652
               */
 
2653
              usb_speed = sysfs_get_double (s, "speed");
 
2654
              if (usb_speed > 0)
 
2655
                {
 
2656
                  connection_interface = "usb";
 
2657
                  connection_speed = usb_speed * (1000 * 1000);
 
2658
                  break;
 
2659
 
 
2660
                }
 
2661
            }
 
2662
          else if (strcmp (subsystem, "firewire") == 0 || strcmp (subsystem, "ieee1394") == 0)
 
2663
            {
 
2664
 
 
2665
              /* TODO: krh has promised a speed file in sysfs; theoretically, the speed can
 
2666
               *       be anything from 100, 200, 400, 800 and 3200. Till then we just hardcode
 
2667
               *       a resonable default of 400 Mbit/s.
 
2668
               */
 
2669
 
 
2670
              connection_interface = "firewire";
 
2671
              connection_speed = 400 * (1000 * 1000);
 
2672
              break;
 
2673
 
 
2674
            }
 
2675
          else if (strcmp (subsystem, "mmc") == 0)
 
2676
            {
 
2677
 
 
2678
              /* TODO: what about non-SD, e.g. MMC? Is that another bus? */
 
2679
              connection_interface = "sdio";
 
2680
 
 
2681
              /* Set vendor name. According to this MMC document
 
2682
               *
 
2683
               * http://www.mmca.org/membership/IAA_Agreement_10_12_06.pdf
 
2684
               *
 
2685
               *  - manfid: the manufacturer id
 
2686
               *  - oemid: the customer of the manufacturer
 
2687
               *
 
2688
               * Apparently these numbers are kept secret. It would be nice
 
2689
               * to map these into names for setting the manufacturer of the drive,
 
2690
               * e.g. Panasonic, Sandisk etc.
 
2691
               */
 
2692
 
 
2693
              model = sysfs_get_string (s, "name");
 
2694
              if (model != NULL)
 
2695
                {
 
2696
                  g_strstrip (model);
 
2697
                  /* Don't overwrite what we set earlier from ID_MODEL */
 
2698
                  if (device->priv->drive_model == NULL)
 
2699
                    {
 
2700
                      q = _dupv8 (model);
 
2701
                      device_set_drive_model (device, q);
 
2702
                      g_free (q);
 
2703
                    }
 
2704
                  g_free (model);
 
2705
                }
 
2706
 
 
2707
              serial = sysfs_get_string (s, "serial");
 
2708
              if (serial != NULL)
 
2709
                {
 
2710
                  g_strstrip (serial);
 
2711
                  /* Don't overwrite what we set earlier from ID_SERIAL */
 
2712
                  if (device->priv->drive_serial == NULL)
 
2713
                    {
 
2714
                      /* this is formatted as a hexnumber; drop the leading 0x */
 
2715
                      q = _dupv8 (serial + 2);
 
2716
                      device_set_drive_serial (device, q);
 
2717
                      g_free (q);
 
2718
                    }
 
2719
                  g_free (serial);
 
2720
                }
 
2721
 
 
2722
              /* TODO: use hwrev and fwrev files? */
 
2723
              revision = sysfs_get_string (s, "date");
 
2724
              if (revision != NULL)
 
2725
                {
 
2726
                  g_strstrip (revision);
 
2727
                  /* Don't overwrite what we set earlier from ID_REVISION */
 
2728
                  if (device->priv->drive_revision == NULL)
 
2729
                    {
 
2730
                      q = _dupv8 (revision);
 
2731
                      device_set_drive_revision (device, q);
 
2732
                      g_free (q);
 
2733
                    }
 
2734
                  g_free (revision);
 
2735
                }
 
2736
 
 
2737
              /* TODO: interface speed; the kernel driver knows; would be nice
 
2738
               * if it could export it */
 
2739
 
 
2740
            }
 
2741
          else if (strcmp (subsystem, "platform") == 0)
 
2742
            {
 
2743
              const gchar *sysfs_name;
 
2744
 
 
2745
              sysfs_name = g_strrstr (s, "/");
 
2746
              if (g_str_has_prefix (sysfs_name + 1, "floppy."))
 
2747
                {
 
2748
                  device_set_drive_vendor (device, "Floppy Drive");
 
2749
                  connection_interface = "platform";
 
2750
                }
 
2751
            }
 
2752
 
 
2753
          g_free (subsystem);
 
2754
        }
 
2755
 
 
2756
      /* advance up the chain */
 
2757
      p = g_strrstr (s, "/");
 
2758
      if (p == NULL)
 
2759
        break;
 
2760
      *p = '\0';
 
2761
 
 
2762
      /* but stop at the root */
 
2763
      if (strcmp (s, "/sys/devices") == 0)
 
2764
        break;
 
2765
 
 
2766
    }
 
2767
  while (TRUE);
 
2768
 
 
2769
  if (connection_interface != NULL)
 
2770
    {
 
2771
      device_set_drive_connection_interface (device, connection_interface);
 
2772
      device_set_drive_connection_speed (device, connection_speed);
 
2773
    }
 
2774
 
 
2775
  g_free (s);
 
2776
}
 
2777
 
 
2778
static const struct
 
2779
{
 
2780
  const gchar *udev_property;
 
2781
  const gchar *media_name;
 
2782
} drive_media_mapping[] =
 
2783
  {
 
2784
    { "ID_DRIVE_FLASH", "flash" },
 
2785
    { "ID_DRIVE_FLASH_CF", "flash_cf" },
 
2786
    { "ID_DRIVE_FLASH_MS", "flash_ms" },
 
2787
    { "ID_DRIVE_FLASH_SM", "flash_sm" },
 
2788
    { "ID_DRIVE_FLASH_SD", "flash_sd" },
 
2789
    { "ID_DRIVE_FLASH_SDHC", "flash_sdhc" },
 
2790
    { "ID_DRIVE_FLASH_MMC", "flash_mmc" },
 
2791
    { "ID_DRIVE_FLOPPY", "floppy" },
 
2792
    { "ID_DRIVE_FLOPPY_ZIP", "floppy_zip" },
 
2793
    { "ID_DRIVE_FLOPPY_JAZ", "floppy_jaz" },
 
2794
    { "ID_CDROM", "optical_cd" },
 
2795
    { "ID_CDROM_CD_R", "optical_cd_r" },
 
2796
    { "ID_CDROM_CD_RW", "optical_cd_rw" },
 
2797
    { "ID_CDROM_DVD", "optical_dvd" },
 
2798
    { "ID_CDROM_DVD_R", "optical_dvd_r" },
 
2799
    { "ID_CDROM_DVD_RW", "optical_dvd_rw" },
 
2800
    { "ID_CDROM_DVD_RAM", "optical_dvd_ram" },
 
2801
    { "ID_CDROM_DVD_PLUS_R", "optical_dvd_plus_r" },
 
2802
    { "ID_CDROM_DVD_PLUS_RW", "optical_dvd_plus_rw" },
 
2803
    { "ID_CDROM_DVD_PLUS_R_DL", "optical_dvd_plus_r_dl" },
 
2804
    { "ID_CDROM_DVD_PLUS_RW_DL", "optical_dvd_plus_rw_dl" },
 
2805
    { "ID_CDROM_BD", "optical_bd" },
 
2806
    { "ID_CDROM_BD_R", "optical_bd_r" },
 
2807
    { "ID_CDROM_BD_RE", "optical_bd_re" },
 
2808
    { "ID_CDROM_HDDVD", "optical_hddvd" },
 
2809
    { "ID_CDROM_HDDVD_R", "optical_hddvd_r" },
 
2810
    { "ID_CDROM_HDDVD_RW", "optical_hddvd_rw" },
 
2811
    { "ID_CDROM_MO", "optical_mo" },
 
2812
    { "ID_CDROM_MRW", "optical_mrw" },
 
2813
    { "ID_CDROM_MRW_W", "optical_mrw_w" },
 
2814
    { NULL, NULL }, };
 
2815
 
 
2816
static const struct
 
2817
{
 
2818
  const gchar *udev_property;
 
2819
  const gchar *media_name;
 
2820
} media_mapping[] =
 
2821
  {
 
2822
    { "ID_DRIVE_MEDIA_FLASH", "flash" },
 
2823
    { "ID_DRIVE_MEDIA_FLASH_CF", "flash_cf" },
 
2824
    { "ID_DRIVE_MEDIA_FLASH_MS", "flash_ms" },
 
2825
    { "ID_DRIVE_MEDIA_FLASH_SM", "flash_sm" },
 
2826
    { "ID_DRIVE_MEDIA_FLASH_SD", "flash_sd" },
 
2827
    { "ID_DRIVE_MEDIA_FLASH_SDHC", "flash_sdhc" },
 
2828
    { "ID_DRIVE_MEDIA_FLASH_MMC", "flash_mmc" },
 
2829
    { "ID_DRIVE_MEDIA_FLOPPY", "floppy" },
 
2830
    { "ID_DRIVE_MEDIA_FLOPPY_ZIP", "floppy_zip" },
 
2831
    { "ID_DRIVE_MEDIA_FLOPPY_JAZ", "floppy_jaz" },
 
2832
    { "ID_CDROM_MEDIA_CD", "optical_cd" },
 
2833
    { "ID_CDROM_MEDIA_CD_R", "optical_cd_r" },
 
2834
    { "ID_CDROM_MEDIA_CD_RW", "optical_cd_rw" },
 
2835
    { "ID_CDROM_MEDIA_DVD", "optical_dvd" },
 
2836
    { "ID_CDROM_MEDIA_DVD_R", "optical_dvd_r" },
 
2837
    { "ID_CDROM_MEDIA_DVD_RW", "optical_dvd_rw" },
 
2838
    { "ID_CDROM_MEDIA_DVD_RAM", "optical_dvd_ram" },
 
2839
    { "ID_CDROM_MEDIA_DVD_PLUS_R", "optical_dvd_plus_r" },
 
2840
    { "ID_CDROM_MEDIA_DVD_PLUS_RW", "optical_dvd_plus_rw" },
 
2841
    { "ID_CDROM_MEDIA_DVD_PLUS_R_DL", "optical_dvd_plus_r_dl" },
 
2842
    { "ID_CDROM_MEDIA_DVD_PLUS_RW_DL", "optical_dvd_plus_rw_dl" },
 
2843
    { "ID_CDROM_MEDIA_BD", "optical_bd" },
 
2844
    { "ID_CDROM_MEDIA_BD_R", "optical_bd_r" },
 
2845
    { "ID_CDROM_MEDIA_BD_RE", "optical_bd_re" },
 
2846
    { "ID_CDROM_MEDIA_HDDVD", "optical_hddvd" },
 
2847
    { "ID_CDROM_MEDIA_HDDVD_R", "optical_hddvd_r" },
 
2848
    { "ID_CDROM_MEDIA_HDDVD_RW", "optical_hddvd_rw" },
 
2849
    { "ID_CDROM_MEDIA_MO", "optical_mo" },
 
2850
    { "ID_CDROM_MEDIA_MRW", "optical_mrw" },
 
2851
    { "ID_CDROM_MEDIA_MRW_W", "optical_mrw_w" },
 
2852
    { NULL, NULL }, };
 
2853
 
 
2854
/* update drive_* properties */
 
2855
static gboolean
 
2856
update_info_drive (Device *device)
 
2857
{
 
2858
  GPtrArray *media_compat_array;
 
2859
  const gchar *media_in_drive;
 
2860
  gboolean drive_is_ejectable;
 
2861
  gboolean drive_can_detach;
 
2862
  gchar *decoded_string;
 
2863
  guint n;
 
2864
 
 
2865
  if (g_udev_device_has_property (device->priv->d, "ID_VENDOR_ENC"))
 
2866
    {
 
2867
      decoded_string = decode_udev_encoded_string (g_udev_device_get_property (device->priv->d, "ID_VENDOR_ENC"));
 
2868
      g_strstrip (decoded_string);
 
2869
      device_set_drive_vendor (device, decoded_string);
 
2870
      g_free (decoded_string);
 
2871
    }
 
2872
  else if (g_udev_device_has_property (device->priv->d, "ID_VENDOR"))
 
2873
    {
 
2874
      device_set_drive_vendor (device, g_udev_device_get_property (device->priv->d, "ID_VENDOR"));
 
2875
    }
 
2876
 
 
2877
  if (g_udev_device_has_property (device->priv->d, "ID_MODEL_ENC"))
 
2878
    {
 
2879
      decoded_string = decode_udev_encoded_string (g_udev_device_get_property (device->priv->d, "ID_MODEL_ENC"));
 
2880
      g_strstrip (decoded_string);
 
2881
      device_set_drive_model (device, decoded_string);
 
2882
      g_free (decoded_string);
 
2883
    }
 
2884
  else if (g_udev_device_has_property (device->priv->d, "ID_MODEL"))
 
2885
    {
 
2886
      device_set_drive_model (device, g_udev_device_get_property (device->priv->d, "ID_MODEL"));
 
2887
    }
 
2888
 
 
2889
  if (g_udev_device_has_property (device->priv->d, "ID_REVISION"))
 
2890
    device_set_drive_revision (device, g_udev_device_get_property (device->priv->d, "ID_REVISION"));
 
2891
  if (g_udev_device_has_property (device->priv->d, "ID_SCSI_SERIAL"))
 
2892
    {
 
2893
      /* scsi_id sometimes use the WWN as the serial - annoying - see
 
2894
       * http://git.kernel.org/?p=linux/hotplug/udev.git;a=commit;h=4e9fdfccbdd16f0cfdb5c8fa8484a8ba0f2e69d3
 
2895
       * for details
 
2896
       */
 
2897
      device_set_drive_serial (device, g_udev_device_get_property (device->priv->d, "ID_SCSI_SERIAL"));
 
2898
    }
 
2899
  else if (g_udev_device_has_property (device->priv->d, "ID_SERIAL_SHORT"))
 
2900
    {
 
2901
      device_set_drive_serial (device, g_udev_device_get_property (device->priv->d, "ID_SERIAL_SHORT"));
 
2902
    }
 
2903
 
 
2904
  if (g_udev_device_has_property (device->priv->d, "ID_WWN_WITH_EXTENSION"))
 
2905
    device_set_drive_wwn (device, g_udev_device_get_property (device->priv->d, "ID_WWN_WITH_EXTENSION") + 2);
 
2906
  else if (g_udev_device_has_property (device->priv->d, "ID_WWN"))
 
2907
    device_set_drive_wwn (device, g_udev_device_get_property (device->priv->d, "ID_WWN") + 2);
 
2908
 
 
2909
  /* pick up some things (vendor, model, connection_interface, connection_speed)
 
2910
   * not (yet) exported by udev helpers
 
2911
   */
 
2912
  update_drive_properties_from_sysfs (device);
 
2913
 
 
2914
  if (g_udev_device_has_property (device->priv->d, "ID_DRIVE_EJECTABLE"))
 
2915
    {
 
2916
      drive_is_ejectable = g_udev_device_get_property_as_boolean (device->priv->d, "ID_DRIVE_EJECTABLE");
 
2917
    }
 
2918
  else
 
2919
    {
 
2920
      drive_is_ejectable = FALSE;
 
2921
      drive_is_ejectable |= g_udev_device_has_property (device->priv->d, "ID_CDROM");
 
2922
      drive_is_ejectable |= g_udev_device_has_property (device->priv->d, "ID_DRIVE_FLOPPY_ZIP");
 
2923
      drive_is_ejectable |= g_udev_device_has_property (device->priv->d, "ID_DRIVE_FLOPPY_JAZ");
 
2924
    }
 
2925
  device_set_drive_is_media_ejectable (device, drive_is_ejectable);
 
2926
 
 
2927
  media_compat_array = g_ptr_array_new ();
 
2928
  for (n = 0; drive_media_mapping[n].udev_property != NULL; n++)
 
2929
    {
 
2930
      if (!g_udev_device_has_property (device->priv->d, drive_media_mapping[n].udev_property))
 
2931
        continue;
 
2932
 
 
2933
      g_ptr_array_add (media_compat_array, (gpointer) drive_media_mapping[n].media_name);
 
2934
    }
 
2935
  /* special handling for SDIO since we don't yet have a sdio_id helper in udev to set properties */
 
2936
  if (g_strcmp0 (device->priv->drive_connection_interface, "sdio") == 0)
 
2937
    {
 
2938
      gchar *type;
 
2939
 
 
2940
      type = sysfs_get_string (device->priv->native_path, "../../type");
 
2941
      g_strstrip (type);
 
2942
      if (g_strcmp0 (type, "MMC") == 0)
 
2943
        {
 
2944
          g_ptr_array_add (media_compat_array, "flash_mmc");
 
2945
        }
 
2946
      else if (g_strcmp0 (type, "SD") == 0)
 
2947
        {
 
2948
          g_ptr_array_add (media_compat_array, "flash_sd");
 
2949
        }
 
2950
      else if (g_strcmp0 (type, "SDHC") == 0)
 
2951
        {
 
2952
          g_ptr_array_add (media_compat_array, "flash_sdhc");
 
2953
        }
 
2954
      g_free (type);
 
2955
    }
 
2956
  g_ptr_array_sort (media_compat_array, (GCompareFunc) ptr_str_array_compare);
 
2957
  g_ptr_array_add (media_compat_array, NULL);
 
2958
  device_set_drive_media_compatibility (device, (GStrv) media_compat_array->pdata);
 
2959
 
 
2960
  media_in_drive = NULL;
 
2961
 
 
2962
  if (device->priv->device_is_media_available)
 
2963
    {
 
2964
      for (n = 0; media_mapping[n].udev_property != NULL; n++)
 
2965
        {
 
2966
          if (!g_udev_device_has_property (device->priv->d, media_mapping[n].udev_property))
 
2967
            continue;
 
2968
 
 
2969
          media_in_drive = drive_media_mapping[n].media_name;
 
2970
          break;
 
2971
        }
 
2972
      /* If the media isn't set (from e.g. udev rules), just pick the first one in media_compat - note
 
2973
       * that this may be NULL (if we don't know what media is compatible with the drive) which is OK.
 
2974
       */
 
2975
      if (media_in_drive == NULL)
 
2976
        media_in_drive = ((const gchar **) media_compat_array->pdata)[0];
 
2977
    }
 
2978
  device_set_drive_media (device, media_in_drive);
 
2979
 
 
2980
  g_ptr_array_free (media_compat_array, TRUE);
 
2981
 
 
2982
  /* right now, we only offer to detach USB devices */
 
2983
  drive_can_detach = FALSE;
 
2984
  if (g_strcmp0 (device->priv->drive_connection_interface, "usb") == 0)
 
2985
    {
 
2986
      drive_can_detach = TRUE;
 
2987
    }
 
2988
  if (g_udev_device_has_property (device->priv->d, "ID_DRIVE_DETACHABLE"))
 
2989
    {
 
2990
      drive_can_detach = g_udev_device_get_property_as_boolean (device->priv->d, "ID_DRIVE_DETACHABLE");
 
2991
    }
 
2992
  device_set_drive_can_detach (device, drive_can_detach);
 
2993
 
 
2994
  /* rotational is in sysfs */
 
2995
  device_set_drive_is_rotational (device, g_udev_device_get_sysfs_attr_as_boolean (device->priv->d, "queue/rotational"));
 
2996
 
 
2997
  if (g_udev_device_has_property (device->priv->d, "ID_ATA_ROTATION_RATE_RPM"))
 
2998
    {
 
2999
      device_set_drive_rotation_rate (device, g_udev_device_get_property_as_int (device->priv->d,
 
3000
                                                                                 "ID_ATA_ROTATION_RATE_RPM"));
 
3001
    }
 
3002
 
 
3003
  if (g_udev_device_get_property_as_boolean (device->priv->d, "ID_ATA_WRITE_CACHE"))
 
3004
    {
 
3005
      if (g_udev_device_get_property_as_boolean (device->priv->d, "ID_ATA_WRITE_CACHE_ENABLED"))
 
3006
        {
 
3007
          device_set_drive_write_cache (device, "enabled");
 
3008
        }
 
3009
      else
 
3010
        {
 
3011
          device_set_drive_write_cache (device, "disabled");
 
3012
        }
 
3013
    }
 
3014
 
 
3015
  return TRUE;
 
3016
}
 
3017
 
 
3018
/* ---------------------------------------------------------------------------------------------------- */
 
3019
 
 
3020
/* update drive_can_spindown property */
 
3021
static gboolean
 
3022
update_info_drive_can_spindown (Device *device)
 
3023
{
 
3024
  gboolean drive_can_spindown;
 
3025
 
 
3026
  /* Right now we only know how to spin down ATA devices (including those USB devices
 
3027
   * that can do ATA SMART)
 
3028
   *
 
3029
   * This would probably also work for SCSI devices (since the helper is doing SCSI
 
3030
   * STOP (which translated in libata to ATA's STANDBY IMMEDIATE) - but that needs
 
3031
   * testing...
 
3032
   */
 
3033
  drive_can_spindown = FALSE;
 
3034
  if (g_strcmp0 (device->priv->drive_connection_interface, "ata") == 0 || device->priv->drive_ata_smart_is_available)
 
3035
    {
 
3036
      drive_can_spindown = TRUE;
 
3037
    }
 
3038
  if (g_udev_device_has_property (device->priv->d, "ID_DRIVE_CAN_SPINDOWN"))
 
3039
    {
 
3040
      drive_can_spindown = g_udev_device_get_property_as_boolean (device->priv->d, "ID_DRIVE_CAN_SPINDOWN");
 
3041
    }
 
3042
  device_set_drive_can_spindown (device, drive_can_spindown);
 
3043
 
 
3044
  return TRUE;
 
3045
}
 
3046
 
 
3047
/* ---------------------------------------------------------------------------------------------------- */
 
3048
 
 
3049
/* update device_is_optical_disc and optical_disc_* properties */
 
3050
static gboolean
 
3051
update_info_optical_disc (Device *device)
 
3052
{
 
3053
  const gchar *cdrom_disc_state;
 
3054
  gint cdrom_track_count;
 
3055
  gint cdrom_track_count_audio;
 
3056
  gint cdrom_session_count;
 
3057
 
 
3058
  /* device_is_optical_disc and optical_disc_* */
 
3059
  if (g_udev_device_has_property (device->priv->d, "ID_CDROM_MEDIA"))
 
3060
    {
 
3061
      device_set_device_is_optical_disc (device, TRUE);
 
3062
 
 
3063
      cdrom_track_count = 0;
 
3064
      cdrom_track_count_audio = 0;
 
3065
      cdrom_session_count = 0;
 
3066
 
 
3067
      if (g_udev_device_has_property (device->priv->d, "ID_CDROM_MEDIA_TRACK_COUNT"))
 
3068
        cdrom_track_count = g_udev_device_get_property_as_int (device->priv->d, "ID_CDROM_MEDIA_TRACK_COUNT");
 
3069
      if (g_udev_device_has_property (device->priv->d, "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO"))
 
3070
        cdrom_track_count_audio = g_udev_device_get_property_as_int (device->priv->d,
 
3071
                                                                     "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO");
 
3072
      if (g_udev_device_has_property (device->priv->d, "ID_CDROM_MEDIA_SESSION_COUNT"))
 
3073
        cdrom_session_count = g_udev_device_get_property_as_int (device->priv->d, "ID_CDROM_MEDIA_SESSION_COUNT");
 
3074
      device_set_optical_disc_num_tracks (device, cdrom_track_count);
 
3075
      device_set_optical_disc_num_audio_tracks (device, cdrom_track_count_audio);
 
3076
      device_set_optical_disc_num_sessions (device, cdrom_session_count);
 
3077
      cdrom_disc_state = g_udev_device_get_property (device->priv->d, "ID_CDROM_MEDIA_STATE");
 
3078
      device_set_optical_disc_is_blank (device, g_strcmp0 (cdrom_disc_state, "blank") == 0);
 
3079
      device_set_optical_disc_is_appendable (device, g_strcmp0 (cdrom_disc_state, "appendable") == 0);
 
3080
      device_set_optical_disc_is_closed (device, g_strcmp0 (cdrom_disc_state, "complete") == 0);
 
3081
    }
 
3082
  else
 
3083
    {
 
3084
      device_set_device_is_optical_disc (device, FALSE);
 
3085
 
 
3086
      device_set_optical_disc_num_tracks (device, 0);
 
3087
      device_set_optical_disc_num_audio_tracks (device, 0);
 
3088
      device_set_optical_disc_num_sessions (device, 0);
 
3089
      device_set_optical_disc_is_blank (device, FALSE);
 
3090
      device_set_optical_disc_is_appendable (device, FALSE);
 
3091
      device_set_optical_disc_is_closed (device, FALSE);
 
3092
    }
 
3093
 
 
3094
  return TRUE;
 
3095
}
 
3096
 
 
3097
/* ---------------------------------------------------------------------------------------------------- */
 
3098
 
 
3099
/* update device_is_luks and luks_holder properties */
 
3100
static gboolean
 
3101
update_info_luks (Device *device)
 
3102
{
 
3103
  if (g_strcmp0 (device->priv->id_type, "crypto_LUKS") == 0 && device->priv->holders_objpath->len == 1)
 
3104
    {
 
3105
      device_set_device_is_luks (device, TRUE);
 
3106
      device_set_luks_holder (device, device->priv->holders_objpath->pdata[0]);
 
3107
    }
 
3108
  else
 
3109
    {
 
3110
      device_set_device_is_luks (device, FALSE);
 
3111
      device_set_luks_holder (device, NULL);
 
3112
    }
 
3113
 
 
3114
  return TRUE;
 
3115
}
 
3116
 
 
3117
/* ---------------------------------------------------------------------------------------------------- */
 
3118
 
 
3119
/* update device_is_luks_cleartext and luks_cleartext_* properties */
 
3120
static gboolean
 
3121
update_info_luks_cleartext (Device *device)
 
3122
{
 
3123
  uid_t unlocked_by_uid;
 
3124
  const gchar *dkd_dm_name;
 
3125
  const gchar *dkd_dm_target_types;
 
3126
  gboolean ret;
 
3127
 
 
3128
  ret = FALSE;
 
3129
 
 
3130
  dkd_dm_name = g_udev_device_get_property (device->priv->d, "DM_NAME");
 
3131
  dkd_dm_target_types = g_udev_device_get_property (device->priv->d, "UDISKS_DM_TARGETS_TYPE");
 
3132
  if (dkd_dm_name != NULL && g_strcmp0 (dkd_dm_target_types, "crypt") == 0 && device->priv->slaves_objpath->len == 1)
 
3133
    {
 
3134
 
 
3135
      /* TODO: might be racing with setting is_drive earlier */
 
3136
      device_set_device_is_drive (device, FALSE);
 
3137
 
 
3138
      if (g_str_has_prefix (dkd_dm_name, "temporary-cryptsetup-"))
 
3139
        {
 
3140
          /* ignore temporary devices created by /sbin/cryptsetup */
 
3141
          goto out;
 
3142
        }
 
3143
 
 
3144
      device_set_device_is_luks_cleartext (device, TRUE);
 
3145
 
 
3146
      device_set_luks_cleartext_slave (device, ((gchar **) device->priv->slaves_objpath->pdata)[0]);
 
3147
 
 
3148
      if (luks_get_uid_from_dm_name (dkd_dm_name, &unlocked_by_uid))
 
3149
        {
 
3150
          device_set_luks_cleartext_unlocked_by_uid (device, unlocked_by_uid);
 
3151
        }
 
3152
 
 
3153
      /* TODO: export this at some point */
 
3154
      device_set_dm_name (device, dkd_dm_name);
 
3155
    }
 
3156
  else
 
3157
    {
 
3158
      device_set_device_is_luks_cleartext (device, FALSE);
 
3159
      device_set_luks_cleartext_slave (device, NULL);
 
3160
    }
 
3161
 
 
3162
  ret = TRUE;
 
3163
 
 
3164
 out:
 
3165
  return ret;
 
3166
}
 
3167
 
 
3168
/* ---------------------------------------------------------------------------------------------------- */
 
3169
 
 
3170
#ifdef HAVE_LVM2
 
3171
static gchar *
 
3172
extract_lvm_uuid (const gchar *s)
 
3173
{
 
3174
  GString *str;
 
3175
 
 
3176
  if (s == NULL || strlen (s) < 32)
 
3177
    return NULL;
 
3178
 
 
3179
  str = g_string_new_len (s, 6);   g_string_append_c (str, '-'); s += 6;
 
3180
  g_string_append_len (str, s, 4); g_string_append_c (str, '-'); s += 4;
 
3181
  g_string_append_len (str, s, 4); g_string_append_c (str, '-'); s += 4;
 
3182
  g_string_append_len (str, s, 4); g_string_append_c (str, '-'); s += 4;
 
3183
  g_string_append_len (str, s, 4); g_string_append_c (str, '-'); s += 4;
 
3184
  g_string_append_len (str, s, 4); g_string_append_c (str, '-'); s += 4;
 
3185
  g_string_append_len (str, s, 6);
 
3186
 
 
3187
  return g_string_free (str, FALSE);
 
3188
}
 
3189
 
 
3190
/* update device_is_linux_lvm2_lv and linux_lvm2_lv_* properties */
 
3191
static gboolean
 
3192
update_info_linux_lvm2_lv (Device *device)
 
3193
{
 
3194
  const gchar *lv_name;
 
3195
  const gchar *vg_name;
 
3196
  const gchar *uuid;
 
3197
  gchar *lv_uuid;
 
3198
  gchar *vg_uuid;
 
3199
  gboolean is_lv;
 
3200
 
 
3201
  is_lv = FALSE;
 
3202
  lv_uuid = NULL;
 
3203
  vg_uuid = NULL;
 
3204
 
 
3205
  lv_name = g_udev_device_get_property (device->priv->d, "DM_LV_NAME");
 
3206
  vg_name = g_udev_device_get_property (device->priv->d, "DM_VG_NAME");
 
3207
 
 
3208
  if (lv_name == NULL || vg_name == NULL)
 
3209
    goto out;
 
3210
 
 
3211
  uuid = g_udev_device_get_sysfs_attr (device->priv->d, "dm/uuid");
 
3212
  if (uuid == NULL || !g_str_has_prefix (uuid, "LVM-"))
 
3213
    goto out;
 
3214
 
 
3215
  vg_uuid = extract_lvm_uuid (uuid + 4);
 
3216
  if (vg_uuid == NULL)
 
3217
    goto out;
 
3218
 
 
3219
  lv_uuid = extract_lvm_uuid (uuid + 4 + 32);
 
3220
  if (lv_uuid == NULL)
 
3221
    goto out;
 
3222
 
 
3223
  is_lv = TRUE;
 
3224
  device_set_linux_lvm2_lv_name (device, lv_name);
 
3225
  device_set_linux_lvm2_lv_uuid (device, lv_uuid);
 
3226
  device_set_linux_lvm2_lv_group_name (device, vg_name);
 
3227
  device_set_linux_lvm2_lv_group_uuid (device, vg_uuid);
 
3228
 
 
3229
  device_set_device_is_drive (device, FALSE);
 
3230
  device_set_device_is_partition (device, FALSE);
 
3231
 
 
3232
 out:
 
3233
  device_set_device_is_linux_lvm2_lv (device, is_lv);
 
3234
  g_free (vg_uuid);
 
3235
  g_free (lv_uuid);
 
3236
  return TRUE;
 
3237
}
 
3238
#endif
 
3239
 
 
3240
/* ---------------------------------------------------------------------------------------------------- */
 
3241
 
 
3242
#ifdef HAVE_DMMP
 
3243
/* update device_is_linux_dmmp and linux_dmmp_* properties */
 
3244
static gboolean
 
3245
update_info_linux_dmmp (Device *device)
 
3246
{
 
3247
  const gchar *dm_name;
 
3248
  const gchar* const *target_types;
 
3249
  const gchar* const *target_parameters;
 
3250
  gchar *decoded_params;
 
3251
  gboolean is_dmmp;
 
3252
  guint n;
 
3253
  GPtrArray *p;
 
3254
  Device *component;
 
3255
  gchar *s;
 
3256
 
 
3257
  is_dmmp = FALSE;
 
3258
  p = NULL;
 
3259
  decoded_params = NULL;
 
3260
 
 
3261
  dm_name = g_udev_device_get_property (device->priv->d, "DM_NAME");
 
3262
  if (dm_name == NULL)
 
3263
    goto out;
 
3264
 
 
3265
  target_types = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_DM_TARGETS_TYPE");
 
3266
  if (target_types == NULL || g_strcmp0 (target_types[0], "multipath") != 0)
 
3267
    goto out;
 
3268
 
 
3269
  if (device->priv->slaves_objpath->len == 0)
 
3270
    goto out;
 
3271
 
 
3272
  target_parameters = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_DM_TARGETS_PARAMS");
 
3273
  if (target_parameters == NULL || g_strv_length ((gchar **) target_parameters) != 1)
 
3274
    goto out;
 
3275
  decoded_params = decode_udev_encoded_string (target_parameters[0]);
 
3276
 
 
3277
  device_set_linux_dmmp_name (device, dm_name);
 
3278
 
 
3279
  device_set_linux_dmmp_parameters (device, decoded_params);
 
3280
 
 
3281
  p = g_ptr_array_new ();
 
3282
  component = NULL;
 
3283
  for (n = 0; n < device->priv->slaves_objpath->len; n++)
 
3284
    {
 
3285
      const gchar *component_objpath = device->priv->slaves_objpath->pdata[n];
 
3286
      if (component == NULL)
 
3287
        {
 
3288
          component = daemon_local_find_by_object_path (device->priv->daemon, component_objpath);
 
3289
        }
 
3290
      g_ptr_array_add (p, (gpointer) component_objpath);
 
3291
    }
 
3292
  g_ptr_array_add (p, NULL);
 
3293
  device_set_linux_dmmp_slaves (device, (GStrv) p->pdata);
 
3294
 
 
3295
  if (component == NULL)
 
3296
    goto out;
 
3297
 
 
3298
  /* Copy only drive properties used for identification to the multipath device. Yes,
 
3299
   * this means, we'll get serial/wwn clashes but this is already so for each path.
 
3300
   *
 
3301
   * Also, clients *should* be smart about things and special-handle linux_dmmp and
 
3302
   * linux_dmmp_component devices.
 
3303
   */
 
3304
  device_set_drive_vendor (device, component->priv->drive_vendor);
 
3305
  device_set_drive_model (device, component->priv->drive_model);
 
3306
  device_set_drive_revision (device, component->priv->drive_revision);
 
3307
  device_set_drive_serial (device, component->priv->drive_serial);
 
3308
  device_set_drive_wwn (device, component->priv->drive_wwn);
 
3309
 
 
3310
  /* connection interface */
 
3311
  device_set_drive_connection_interface (device, "virtual_multipath");
 
3312
  device_set_drive_connection_speed (device, 0);
 
3313
 
 
3314
  s = g_strdup_printf ("/dev/mapper/%s", dm_name);
 
3315
  device_set_device_file_presentation (device, s);
 
3316
  g_free (s);
 
3317
 
 
3318
  is_dmmp = TRUE;
 
3319
 
 
3320
 out:
 
3321
  g_free (decoded_params);
 
3322
  if (p != NULL)
 
3323
    g_ptr_array_free (p, TRUE);
 
3324
  device_set_device_is_linux_dmmp (device, is_dmmp);
 
3325
  return TRUE;
 
3326
}
 
3327
#endif
 
3328
 
 
3329
/* ---------------------------------------------------------------------------------------------------- */
 
3330
 
 
3331
#ifdef HAVE_DMMP
 
3332
/* updates device_is_partition and partition_* properties for dm-0 "partitions" on a multi-path device  */
 
3333
static gboolean
 
3334
update_info_partition_on_linux_dmmp (Device *device)
 
3335
{
 
3336
  const gchar *dm_name;
 
3337
  const gchar* const *targets_type;
 
3338
  const gchar* const *targets_params;
 
3339
  gchar *params;
 
3340
  gint linear_slave_major;
 
3341
  gint linear_slave_minor;
 
3342
  guint64 offset_sectors;
 
3343
  Device *linear_slave;
 
3344
  gchar *s;
 
3345
 
 
3346
  params = NULL;
 
3347
 
 
3348
  dm_name = g_udev_device_get_property (device->priv->d, "DM_NAME");
 
3349
  if (dm_name == NULL)
 
3350
    goto out;
 
3351
 
 
3352
  targets_type = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_DM_TARGETS_TYPE");
 
3353
  /* If we ever need this for other types than "linear", remember to update
 
3354
     udisks-dm-export.c as well. */
 
3355
  if (targets_type == NULL || !(g_strcmp0 (targets_type[0], "linear") == 0 ||
 
3356
                                g_strcmp0 (targets_type[0], "multipath") == 0))
 
3357
    goto out;
 
3358
 
 
3359
  targets_params = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_DM_TARGETS_PARAMS");
 
3360
  if (targets_params == NULL)
 
3361
    goto out;
 
3362
  params = decode_udev_encoded_string (targets_params[0]);
 
3363
 
 
3364
  if (sscanf (params,
 
3365
              "%d:%d %" G_GUINT64_FORMAT,
 
3366
              &linear_slave_major,
 
3367
              &linear_slave_minor,
 
3368
              &offset_sectors) != 3)
 
3369
    goto out;
 
3370
 
 
3371
  linear_slave = daemon_local_find_by_dev (device->priv->daemon,
 
3372
                                              makedev (linear_slave_major, linear_slave_minor));
 
3373
  if (linear_slave == NULL)
 
3374
    goto out;
 
3375
  if (!linear_slave->priv->device_is_linux_dmmp)
 
3376
    goto out;
 
3377
 
 
3378
  /* The Partition* properties has been set as part of
 
3379
   * update_info_partition() by reading UDISKS_PARTITION_*
 
3380
   * properties.. so here we bascially just update the presentation
 
3381
   * device file name and and whether the device is a drive.
 
3382
   */
 
3383
 
 
3384
  s = g_strdup_printf ("/dev/mapper/%s", dm_name);
 
3385
  device_set_device_file_presentation (device, s);
 
3386
  g_free (s);
 
3387
 
 
3388
  device_set_device_is_drive (device, FALSE);
 
3389
 
 
3390
 out:
 
3391
  g_free (params);
 
3392
  return TRUE;
 
3393
}
 
3394
#endif
 
3395
 
 
3396
/* ---------------------------------------------------------------------------------------------------- */
 
3397
 
 
3398
#ifdef HAVE_DMMP
 
3399
/* update device_is_linux_dmmp_component and linux_dmmp_component_* properties */
 
3400
static gboolean
 
3401
update_info_linux_dmmp_component (Device *device)
 
3402
{
 
3403
  gboolean is_dmmp_component;
 
3404
 
 
3405
  is_dmmp_component = FALSE;
 
3406
 
 
3407
  if (device->priv->holders_objpath->len == 1)
 
3408
    {
 
3409
      Device *holder;
 
3410
 
 
3411
      holder = daemon_local_find_by_object_path (device->priv->daemon, device->priv->holders_objpath->pdata[0]);
 
3412
      if (holder != NULL && holder->priv->device_is_linux_dmmp)
 
3413
        {
 
3414
          is_dmmp_component = TRUE;
 
3415
          device_set_linux_dmmp_component_holder (device, holder->priv->object_path);
 
3416
        }
 
3417
    }
 
3418
 
 
3419
  device_set_device_is_linux_dmmp_component (device, is_dmmp_component);
 
3420
  return TRUE;
 
3421
}
 
3422
#endif
 
3423
 
 
3424
/* ---------------------------------------------------------------------------------------------------- */
 
3425
 
 
3426
#ifdef HAVE_LVM2
 
3427
/* update device_is_linux_lvm2_pv and linux_lvm2_pv_* properties */
 
3428
static gboolean
 
3429
update_info_linux_lvm2_pv (Device *device)
 
3430
{
 
3431
  const gchar *pv_uuid;
 
3432
  guint64 pv_num_mda;
 
3433
  const gchar *vg_name;
 
3434
  const gchar *vg_uuid;
 
3435
  gboolean is_pv;
 
3436
  guint64 vg_size;
 
3437
  guint64 vg_unallocated_size;
 
3438
  guint64 vg_extent_size;
 
3439
  guint64 vg_seqnum;
 
3440
  const gchar* const *vg_pvs;
 
3441
  const gchar* const *vg_lvs;
 
3442
 
 
3443
  pv_uuid               = g_udev_device_get_property (device->priv->d, "UDISKS_LVM2_PV_UUID");
 
3444
  pv_num_mda            = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_LVM2_PV_NUM_MDA");
 
3445
  vg_name               = g_udev_device_get_property (device->priv->d, "UDISKS_LVM2_PV_VG_NAME");
 
3446
  vg_uuid               = g_udev_device_get_property (device->priv->d, "UDISKS_LVM2_PV_VG_UUID");
 
3447
  vg_size               = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_LVM2_PV_VG_SIZE");
 
3448
  vg_unallocated_size   = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_LVM2_PV_VG_FREE_SIZE");
 
3449
  vg_extent_size        = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_LVM2_PV_VG_EXTENT_SIZE");
 
3450
  vg_seqnum             = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_LVM2_PV_VG_SEQNUM");
 
3451
  vg_pvs                = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_LVM2_PV_VG_PV_LIST");
 
3452
  vg_lvs                = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_LVM2_PV_VG_LV_LIST");
 
3453
 
 
3454
  is_pv = FALSE;
 
3455
 
 
3456
  if (pv_uuid == NULL)
 
3457
    goto out;
 
3458
 
 
3459
  is_pv = TRUE;
 
3460
  device_set_linux_lvm2_pv_uuid (device, pv_uuid);
 
3461
  device_set_linux_lvm2_pv_num_metadata_areas (device, pv_num_mda);
 
3462
  device_set_linux_lvm2_pv_group_name (device, vg_name);
 
3463
  device_set_linux_lvm2_pv_group_uuid (device, vg_uuid);
 
3464
  device_set_linux_lvm2_pv_group_size (device, vg_size);
 
3465
  device_set_linux_lvm2_pv_group_unallocated_size (device, vg_unallocated_size);
 
3466
  device_set_linux_lvm2_pv_group_extent_size (device, vg_extent_size);
 
3467
  device_set_linux_lvm2_pv_group_sequence_number (device, vg_seqnum);
 
3468
  device_set_linux_lvm2_pv_group_physical_volumes (device, (GStrv) vg_pvs);
 
3469
  device_set_linux_lvm2_pv_group_logical_volumes (device, (GStrv) vg_lvs);
 
3470
 
 
3471
 out:
 
3472
  device_set_device_is_linux_lvm2_pv (device, is_pv);
 
3473
  return TRUE;
 
3474
}
 
3475
#endif
 
3476
 
 
3477
/* ---------------------------------------------------------------------------------------------------- */
 
3478
 
 
3479
/* update device_is_linux_md_component and linux_md_component_* properties */
 
3480
static gboolean
 
3481
update_info_linux_md_component (Device *device)
 
3482
{
 
3483
  if (g_strcmp0 (device->priv->id_type, "linux_raid_member") == 0)
 
3484
    {
 
3485
      const gchar *md_comp_level;
 
3486
      gint md_comp_num_raid_devices;
 
3487
      const gchar *md_comp_uuid;
 
3488
      const gchar *md_comp_home_host;
 
3489
      const gchar *md_comp_name;
 
3490
      const gchar *md_comp_version;
 
3491
      gchar *md_name;
 
3492
      gchar *s;
 
3493
      int md_comp_position;
 
3494
 
 
3495
      md_comp_position = -1;
 
3496
 
 
3497
      device_set_device_is_linux_md_component (device, TRUE);
 
3498
 
 
3499
      /* linux_md_component_holder and linux_md_component_state */
 
3500
      if (device->priv->holders_objpath->len == 1)
 
3501
        {
 
3502
          Device *holder;
 
3503
          gchar **state_tokens;
 
3504
 
 
3505
          device_set_linux_md_component_holder (device, device->priv->holders_objpath->pdata[0]);
 
3506
          state_tokens = NULL;
 
3507
          holder = daemon_local_find_by_object_path (device->priv->daemon, device->priv->holders_objpath->pdata[0]);
 
3508
          if (holder != NULL && holder->priv->device_is_linux_md)
 
3509
            {
 
3510
              gchar *dev_name;
 
3511
              gchar *md_dev_path;
 
3512
              gchar *state_contents;
 
3513
              gchar *slot_contents;
 
3514
              gint slot_number;
 
3515
              gchar *endp;
 
3516
 
 
3517
              dev_name = g_path_get_basename (device->priv->native_path);
 
3518
              md_dev_path = g_strdup_printf ("%s/md/dev-%s", holder->priv->native_path, dev_name);
 
3519
              state_contents = sysfs_get_string (md_dev_path, "state");
 
3520
              g_strstrip (state_contents);
 
3521
              state_tokens = g_strsplit (state_contents, ",", 0);
 
3522
 
 
3523
              slot_contents = sysfs_get_string (md_dev_path, "slot");
 
3524
              g_strstrip (slot_contents);
 
3525
              slot_number = strtol (slot_contents, &endp, 0);
 
3526
              if (endp != NULL && *endp == '\0')
 
3527
                {
 
3528
                  md_comp_position = slot_number;
 
3529
                }
 
3530
 
 
3531
              g_free (slot_contents);
 
3532
              g_free (state_contents);
 
3533
              g_free (md_dev_path);
 
3534
              g_free (dev_name);
 
3535
            }
 
3536
 
 
3537
          device_set_linux_md_component_state (device, state_tokens);
 
3538
          g_strfreev (state_tokens);
 
3539
 
 
3540
        }
 
3541
      else
 
3542
        {
 
3543
          /* no holder, nullify properties */
 
3544
          device_set_linux_md_component_holder (device, NULL);
 
3545
          device_set_linux_md_component_state (device, NULL);
 
3546
        }
 
3547
 
 
3548
      md_comp_level = g_udev_device_get_property (device->priv->d, "MD_LEVEL");
 
3549
      md_comp_num_raid_devices = g_udev_device_get_property_as_int (device->priv->d, "MD_DEVICES");
 
3550
      md_comp_uuid = g_udev_device_get_property (device->priv->d, "MD_UUID");
 
3551
      md_name = g_strdup (g_udev_device_get_property (device->priv->d, "MD_NAME"));
 
3552
      s = NULL;
 
3553
      if (md_name != NULL)
 
3554
        s = strstr (md_name, ":");
 
3555
      if (s != NULL)
 
3556
        {
 
3557
          *s = '\0';
 
3558
          md_comp_home_host = md_name;
 
3559
          md_comp_name = s + 1;
 
3560
        }
 
3561
      else
 
3562
        {
 
3563
          md_comp_home_host = "";
 
3564
          md_comp_name = md_name;
 
3565
        }
 
3566
      md_comp_version = device->priv->id_version;
 
3567
 
 
3568
      device_set_linux_md_component_level (device, md_comp_level);
 
3569
      device_set_linux_md_component_position (device, md_comp_position);
 
3570
      device_set_linux_md_component_num_raid_devices (device, md_comp_num_raid_devices);
 
3571
      device_set_linux_md_component_uuid (device, md_comp_uuid);
 
3572
      device_set_linux_md_component_home_host (device, md_comp_home_host);
 
3573
      device_set_linux_md_component_name (device, md_comp_name);
 
3574
      device_set_linux_md_component_version (device, md_comp_version);
 
3575
 
 
3576
      g_free (md_name);
 
3577
    }
 
3578
  else
 
3579
    {
 
3580
      device_set_device_is_linux_md_component (device, FALSE);
 
3581
      device_set_linux_md_component_level (device, NULL);
 
3582
      device_set_linux_md_component_position (device, -1);
 
3583
      device_set_linux_md_component_num_raid_devices (device, 0);
 
3584
      device_set_linux_md_component_uuid (device, NULL);
 
3585
      device_set_linux_md_component_home_host (device, NULL);
 
3586
      device_set_linux_md_component_name (device, NULL);
 
3587
      device_set_linux_md_component_version (device, NULL);
 
3588
      device_set_linux_md_component_holder (device, NULL);
 
3589
      device_set_linux_md_component_state (device, NULL);
 
3590
    }
 
3591
 
 
3592
  return TRUE;
 
3593
}
 
3594
 
 
3595
/* ---------------------------------------------------------------------------------------------------- */
 
3596
 
 
3597
/* update device_is_linux_md and linux_md_* properties */
 
3598
static gboolean
 
3599
update_info_linux_md (Device *device)
 
3600
{
 
3601
  gboolean ret;
 
3602
  guint n;
 
3603
  gchar *s;
 
3604
  gchar *p;
 
3605
 
 
3606
  ret = FALSE;
 
3607
 
 
3608
  if (sysfs_file_exists (device->priv->native_path, "md"))
 
3609
    {
 
3610
      gchar *uuid;
 
3611
      gint num_raid_devices;
 
3612
      gchar *raid_level;
 
3613
      gchar *array_state;
 
3614
      Device *slave;
 
3615
      GPtrArray *md_slaves;
 
3616
      const gchar *md_name;
 
3617
      const gchar *md_home_host;
 
3618
 
 
3619
      device_set_device_is_linux_md (device, TRUE);
 
3620
 
 
3621
      /* figure out if the array is active */
 
3622
      array_state = sysfs_get_string (device->priv->native_path, "md/array_state");
 
3623
      if (array_state == NULL)
 
3624
        {
 
3625
          g_print ("**** NOTE: Linux MD array %s has no array_state file'; removing\n", device->priv->native_path);
 
3626
          goto out;
 
3627
        }
 
3628
      g_strstrip (array_state);
 
3629
 
 
3630
      /* ignore clear arrays since these have no devices, no size, no level */
 
3631
      if (strcmp (array_state, "clear") == 0)
 
3632
        {
 
3633
          g_print ("**** NOTE: Linux MD array %s is 'clear'; removing\n", device->priv->native_path);
 
3634
          g_free (array_state);
 
3635
          goto out;
 
3636
        }
 
3637
 
 
3638
      device_set_linux_md_state (device, array_state);
 
3639
      g_free (array_state);
 
3640
 
 
3641
      /* find a slave from the array */
 
3642
      slave = NULL;
 
3643
      for (n = 0; n < device->priv->slaves_objpath->len; n++)
 
3644
        {
 
3645
          const gchar *slave_objpath;
 
3646
 
 
3647
          slave_objpath = device->priv->slaves_objpath->pdata[n];
 
3648
          slave = daemon_local_find_by_object_path (device->priv->daemon, slave_objpath);
 
3649
          if (slave != NULL)
 
3650
            break;
 
3651
        }
 
3652
 
 
3653
      uuid = g_strdup (g_udev_device_get_property (device->priv->d, "MD_UUID"));
 
3654
      num_raid_devices = sysfs_get_int (device->priv->native_path, "md/raid_disks");
 
3655
      raid_level = g_strstrip (sysfs_get_string (device->priv->native_path, "md/level"));
 
3656
 
 
3657
      if (slave != NULL)
 
3658
        {
 
3659
          /* if the UUID isn't set by the udev rules (array may be inactive) get it from a slave */
 
3660
          if (uuid == NULL || strlen (uuid) == 0)
 
3661
            {
 
3662
              g_free (uuid);
 
3663
              uuid = g_strdup (slave->priv->linux_md_component_uuid);
 
3664
            }
 
3665
 
 
3666
          /* ditto for raid level */
 
3667
          if (raid_level == NULL || strlen (raid_level) == 0)
 
3668
            {
 
3669
              g_free (raid_level);
 
3670
              raid_level = g_strdup (slave->priv->linux_md_component_level);
 
3671
            }
 
3672
 
 
3673
          /* and num_raid_devices too */
 
3674
          if (device->priv->linux_md_num_raid_devices == 0)
 
3675
            {
 
3676
              num_raid_devices = slave->priv->linux_md_component_num_raid_devices;
 
3677
            }
 
3678
        }
 
3679
 
 
3680
      device_set_linux_md_uuid (device, uuid);
 
3681
      device_set_linux_md_num_raid_devices (device, num_raid_devices);
 
3682
      device_set_linux_md_level (device, raid_level);
 
3683
      g_free (raid_level);
 
3684
      g_free (uuid);
 
3685
 
 
3686
      /* infer the array name and homehost */
 
3687
      p = g_strdup (g_udev_device_get_property (device->priv->d, "MD_NAME"));
 
3688
      s = NULL;
 
3689
      if (p != NULL)
 
3690
        s = strstr (p, ":");
 
3691
      if (s != NULL)
 
3692
        {
 
3693
          *s = '\0';
 
3694
          md_home_host = p;
 
3695
          md_name = s + 1;
 
3696
        }
 
3697
      else
 
3698
        {
 
3699
          md_home_host = "";
 
3700
          md_name = p;
 
3701
        }
 
3702
      device_set_linux_md_home_host (device, md_home_host);
 
3703
      device_set_linux_md_name (device, md_name);
 
3704
      g_free (p);
 
3705
 
 
3706
      s = g_strstrip (sysfs_get_string (device->priv->native_path, "md/metadata_version"));
 
3707
      device_set_linux_md_version (device, s);
 
3708
      g_free (s);
 
3709
 
 
3710
      /* Go through all block slaves and build up the linux_md_slaves property
 
3711
       *
 
3712
       * Also update the slaves since the slave state may have changed.
 
3713
       */
 
3714
      md_slaves = g_ptr_array_new ();
 
3715
      for (n = 0; n < device->priv->slaves_objpath->len; n++)
 
3716
        {
 
3717
          Device *slave_device;
 
3718
          const gchar *slave_objpath;
 
3719
 
 
3720
          slave_objpath = device->priv->slaves_objpath->pdata[n];
 
3721
          g_ptr_array_add (md_slaves, (gpointer) slave_objpath);
 
3722
          slave_device = daemon_local_find_by_object_path (device->priv->daemon, slave_objpath);
 
3723
          if (slave_device != NULL)
 
3724
            {
 
3725
              update_info (slave_device);
 
3726
            }
 
3727
        }
 
3728
      g_ptr_array_sort (md_slaves, (GCompareFunc) ptr_str_array_compare);
 
3729
      g_ptr_array_add (md_slaves, NULL);
 
3730
      device_set_linux_md_slaves (device, (GStrv) md_slaves->pdata);
 
3731
      g_ptr_array_free (md_slaves, TRUE);
 
3732
 
 
3733
      /* TODO: may race */
 
3734
      device_set_drive_vendor (device, "Linux");
 
3735
      if (device->priv->linux_md_level != NULL)
 
3736
        s = g_strdup_printf ("Software RAID %s", device->priv->linux_md_level);
 
3737
      else
 
3738
        s = g_strdup_printf ("Software RAID");
 
3739
      device_set_drive_model (device, s);
 
3740
      g_free (s);
 
3741
      device_set_drive_revision (device, device->priv->linux_md_version);
 
3742
      device_set_drive_connection_interface (device, "virtual");
 
3743
      device_set_drive_serial (device, device->priv->linux_md_uuid);
 
3744
 
 
3745
      /* RAID-0 can never resync or run degraded */
 
3746
      if (g_strcmp0 (device->priv->linux_md_level, "raid0") == 0 || g_strcmp0 (device->priv->linux_md_level, "linear")
 
3747
          == 0)
 
3748
        {
 
3749
          device_set_linux_md_sync_action (device, "idle");
 
3750
          device_set_linux_md_is_degraded (device, FALSE);
 
3751
        }
 
3752
      else
 
3753
        {
 
3754
          gchar *degraded_file;
 
3755
          gint num_degraded_devices;
 
3756
 
 
3757
          degraded_file = sysfs_get_string (device->priv->native_path, "md/degraded");
 
3758
          if (degraded_file == NULL)
 
3759
            {
 
3760
              num_degraded_devices = 0;
 
3761
            }
 
3762
          else
 
3763
            {
 
3764
              num_degraded_devices = strtol (degraded_file, NULL, 0);
 
3765
            }
 
3766
          g_free (degraded_file);
 
3767
 
 
3768
          device_set_linux_md_is_degraded (device, (num_degraded_devices > 0));
 
3769
 
 
3770
          s = g_strstrip (sysfs_get_string (device->priv->native_path, "md/sync_action"));
 
3771
          device_set_linux_md_sync_action (device, s);
 
3772
          g_free (s);
 
3773
 
 
3774
          if (device->priv->linux_md_sync_action == NULL || strlen (device->priv->linux_md_sync_action) == 0)
 
3775
            {
 
3776
              device_set_linux_md_sync_action (device, "idle");
 
3777
            }
 
3778
 
 
3779
          /* if not idle; update percentage and speed */
 
3780
          if (g_strcmp0 (device->priv->linux_md_sync_action, "idle") != 0)
 
3781
            {
 
3782
              char *s;
 
3783
              guint64 done;
 
3784
              guint64 remaining;
 
3785
 
 
3786
              s = g_strstrip (sysfs_get_string (device->priv->native_path, "md/sync_completed"));
 
3787
              if (sscanf (s, "%" G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT "", &done, &remaining) == 2)
 
3788
                {
 
3789
                  device_set_linux_md_sync_percentage (device, 100.0 * ((double) done) / ((double) remaining));
 
3790
                }
 
3791
              else
 
3792
                {
 
3793
                  g_warning ("cannot parse md/sync_completed for %s: '%s'", device->priv->native_path, s);
 
3794
                }
 
3795
              g_free (s);
 
3796
 
 
3797
              device_set_linux_md_sync_speed (device, 1000L * sysfs_get_uint64 (device->priv->native_path,
 
3798
                                                                                "md/sync_speed"));
 
3799
 
 
3800
              /* Since the kernel doesn't emit uevents while the job is pending, set up
 
3801
               * a timeout for every two seconds to synthesize the change event so we can
 
3802
               * refresh the completed/speed properties.
 
3803
               */
 
3804
              if (device->priv->linux_md_poll_timeout_id == 0)
 
3805
                {
 
3806
                  device->priv->linux_md_poll_timeout_id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
 
3807
                                                                                       2,
 
3808
                                                                                       poll_syncing_md_device,
 
3809
                                                                                       g_object_ref (device),
 
3810
                                                                                       g_object_unref);
 
3811
                }
 
3812
            }
 
3813
          else
 
3814
            {
 
3815
              device_set_linux_md_sync_percentage (device, 0.0);
 
3816
              device_set_linux_md_sync_speed (device, 0);
 
3817
            }
 
3818
        }
 
3819
 
 
3820
    }
 
3821
  else
 
3822
    {
 
3823
      device_set_device_is_linux_md (device, FALSE);
 
3824
      device_set_linux_md_state (device, NULL);
 
3825
      device_set_linux_md_level (device, NULL);
 
3826
      device_set_linux_md_num_raid_devices (device, 0);
 
3827
      device_set_linux_md_uuid (device, NULL);
 
3828
      device_set_linux_md_home_host (device, NULL);
 
3829
      device_set_linux_md_name (device, NULL);
 
3830
      device_set_linux_md_version (device, NULL);
 
3831
      device_set_linux_md_slaves (device, NULL);
 
3832
      device_set_linux_md_is_degraded (device, FALSE);
 
3833
      device_set_linux_md_sync_action (device, NULL);
 
3834
      device_set_linux_md_sync_percentage (device, 0.0);
 
3835
      device_set_linux_md_sync_speed (device, 0);
 
3836
    }
 
3837
 
 
3838
  ret = TRUE;
 
3839
 
 
3840
 out:
 
3841
  return ret;
 
3842
}
 
3843
 
 
3844
/* ---------------------------------------------------------------------------------------------------- */
 
3845
 
 
3846
/* update drive_ata_smart_* properties */
 
3847
static gboolean
 
3848
update_info_drive_ata_smart (Device *device)
 
3849
{
 
3850
  gboolean ata_smart_is_available;
 
3851
 
 
3852
  ata_smart_is_available = FALSE;
 
3853
  if (device->priv->device_is_drive && g_udev_device_has_property (device->priv->d, "UDISKS_ATA_SMART_IS_AVAILABLE"))
 
3854
    ata_smart_is_available = g_udev_device_get_property_as_boolean (device->priv->d, "UDISKS_ATA_SMART_IS_AVAILABLE");
 
3855
 
 
3856
  device_set_drive_ata_smart_is_available (device, ata_smart_is_available);
 
3857
 
 
3858
  /* NOTE: we don't collect ATA SMART data here, we only set whether the device is ATA SMART capable;
 
3859
   *       collecting data is done in separate routines, see the
 
3860
   *       device_drive_ata_smart_refresh_data() function for details.
 
3861
   */
 
3862
 
 
3863
  return TRUE;
 
3864
}
 
3865
 
 
3866
/* ---------------------------------------------------------------------------------------------------- */
 
3867
 
 
3868
/* device_is_system_internal */
 
3869
static gboolean
 
3870
update_info_is_system_internal (Device *device)
 
3871
{
 
3872
  gboolean is_system_internal;
 
3873
  
 
3874
  if (g_udev_device_has_property (device->priv->d, "UDISKS_SYSTEM_INTERNAL"))
 
3875
    {
 
3876
      is_system_internal = g_udev_device_get_property_as_boolean (device->priv->d, "UDISKS_SYSTEM_INTERNAL");
 
3877
      goto determined;
 
3878
    }
 
3879
 
 
3880
  /* start out by assuming the device is system internal, then adjust depending on what kind of
 
3881
   * device we are dealing with
 
3882
   */
 
3883
  is_system_internal = TRUE;
 
3884
 
 
3885
  /* A Linux MD device is system internal if, and only if
 
3886
   *
 
3887
   * - a single component is system internal
 
3888
   * - there are no components
 
3889
   */
 
3890
  if (device->priv->device_is_linux_md)
 
3891
    {
 
3892
      is_system_internal = FALSE;
 
3893
 
 
3894
      if (device->priv->slaves_objpath->len == 0)
 
3895
        {
 
3896
          is_system_internal = TRUE;
 
3897
        }
 
3898
      else
 
3899
        {
 
3900
          guint n;
 
3901
 
 
3902
          for (n = 0; n < device->priv->slaves_objpath->len; n++)
 
3903
            {
 
3904
              const gchar *slave_objpath;
 
3905
              Device *slave;
 
3906
 
 
3907
              slave_objpath = device->priv->slaves_objpath->pdata[n];
 
3908
              slave = daemon_local_find_by_object_path (device->priv->daemon, slave_objpath);
 
3909
              if (slave == NULL)
 
3910
                continue;
 
3911
 
 
3912
              if (slave->priv->device_is_system_internal)
 
3913
                {
 
3914
                  is_system_internal = TRUE;
 
3915
                  break;
 
3916
                }
 
3917
            }
 
3918
        }
 
3919
 
 
3920
      goto determined;
 
3921
    }
 
3922
 
 
3923
  /* a partition is system internal only if the drive it belongs to is system internal */
 
3924
  if (device->priv->device_is_partition)
 
3925
    {
 
3926
      Device *enclosing_device;
 
3927
 
 
3928
      enclosing_device = daemon_local_find_by_object_path (device->priv->daemon, device->priv->partition_slave);
 
3929
      if (enclosing_device != NULL)
 
3930
        {
 
3931
          is_system_internal = enclosing_device->priv->device_is_system_internal;
 
3932
        }
 
3933
      else
 
3934
        {
 
3935
          is_system_internal = TRUE;
 
3936
        }
 
3937
 
 
3938
      goto determined;
 
3939
    }
 
3940
 
 
3941
  /* a LUKS cleartext device is system internal only if the underlying crypto-text
 
3942
   * device is system internal
 
3943
   */
 
3944
  if (device->priv->device_is_luks_cleartext)
 
3945
    {
 
3946
      Device *enclosing_device;
 
3947
      enclosing_device = daemon_local_find_by_object_path (device->priv->daemon, device->priv->luks_cleartext_slave);
 
3948
      if (enclosing_device != NULL)
 
3949
        {
 
3950
          is_system_internal = enclosing_device->priv->device_is_system_internal;
 
3951
        }
 
3952
      else
 
3953
        {
 
3954
          is_system_internal = TRUE;
 
3955
        }
 
3956
 
 
3957
      goto determined;
 
3958
    }
 
3959
 
 
3960
  /* devices with removable media are never system internal */
 
3961
  if (device->priv->device_is_removable)
 
3962
    {
 
3963
      is_system_internal = FALSE;
 
3964
      goto determined;
 
3965
    }
 
3966
 
 
3967
  /* devices on certain buses are never system internal */
 
3968
  if (device->priv->device_is_drive && device->priv->drive_connection_interface != NULL)
 
3969
    {
 
3970
 
 
3971
      if (strcmp (device->priv->drive_connection_interface, "ata_serial_esata") == 0
 
3972
          || strcmp (device->priv->drive_connection_interface, "sdio") == 0
 
3973
          || strcmp (device->priv->drive_connection_interface, "usb") == 0
 
3974
          || strcmp (device->priv->drive_connection_interface, "firewire") == 0)
 
3975
        {
 
3976
          is_system_internal = FALSE;
 
3977
        }
 
3978
      else
 
3979
        {
 
3980
          is_system_internal = TRUE;
 
3981
        }
 
3982
      goto determined;
 
3983
    }
 
3984
 
 
3985
 determined:
 
3986
  device_set_device_is_system_internal (device, is_system_internal);
 
3987
 
 
3988
  return TRUE;
 
3989
}
 
3990
 
 
3991
/* ---------------------------------------------------------------------------------------------------- */
 
3992
 
 
3993
/* device_is_mounted, device_mount, device_mounted_by_uid */
 
3994
static gboolean
 
3995
update_info_mount_state (Device *device)
 
3996
{
 
3997
  MountMonitor *monitor;
 
3998
  GList *mounts;
 
3999
  gboolean was_mounted;
 
4000
 
 
4001
  mounts = NULL;
 
4002
 
 
4003
  /* defer setting the mount point until FilesystemMount returns and
 
4004
   * the mounts file is written
 
4005
   */
 
4006
  if (device->priv->job_in_progress && g_strcmp0 (device->priv->job_id, "FilesystemMount") == 0)
 
4007
    goto out;
 
4008
 
 
4009
  monitor = daemon_local_get_mount_monitor (device->priv->daemon);
 
4010
 
 
4011
  mounts = mount_monitor_get_mounts_for_dev (monitor, device->priv->dev);
 
4012
 
 
4013
  was_mounted = device->priv->device_is_mounted;
 
4014
 
 
4015
  if (mounts != NULL)
 
4016
    {
 
4017
      GList *l;
 
4018
      guint n;
 
4019
      gchar **mount_paths;
 
4020
 
 
4021
      mount_paths = g_new0 (gchar *, g_list_length (mounts) + 1);
 
4022
      for (l = mounts, n = 0; l != NULL; l = l->next, n++)
 
4023
        {
 
4024
          mount_paths[n] = g_strdup (mount_get_mount_path (MOUNT (l->data)));
 
4025
        }
 
4026
 
 
4027
      device_set_device_is_mounted (device, TRUE);
 
4028
      device_set_device_mount_paths (device, mount_paths);
 
4029
      if (!was_mounted)
 
4030
        {
 
4031
          uid_t mounted_by_uid;
 
4032
 
 
4033
          if (!mount_file_has_device (device->priv->device_file, &mounted_by_uid, NULL))
 
4034
            mounted_by_uid = 0;
 
4035
          device_set_device_mounted_by_uid (device, mounted_by_uid);
 
4036
        }
 
4037
 
 
4038
      g_strfreev (mount_paths);
 
4039
 
 
4040
    }
 
4041
  else
 
4042
    {
 
4043
      gboolean remove_dir_on_unmount;
 
4044
      gchar *old_mount_path;
 
4045
 
 
4046
      old_mount_path = NULL;
 
4047
      if (device->priv->device_mount_paths->len > 0)
 
4048
        old_mount_path = g_strdup (((gchar **) device->priv->device_mount_paths->pdata)[0]);
 
4049
 
 
4050
      device_set_device_is_mounted (device, FALSE);
 
4051
      device_set_device_mount_paths (device, NULL);
 
4052
      device_set_device_mounted_by_uid (device, 0);
 
4053
 
 
4054
      /* clean up stale mount directory */
 
4055
      remove_dir_on_unmount = FALSE;
 
4056
      if (was_mounted && mount_file_has_device (device->priv->device_file, NULL, &remove_dir_on_unmount))
 
4057
        {
 
4058
          mount_file_remove (device->priv->device_file, old_mount_path);
 
4059
          if (remove_dir_on_unmount)
 
4060
            {
 
4061
              if (g_rmdir (old_mount_path) != 0)
 
4062
                {
 
4063
                  g_warning ("Error removing dir '%s' on unmount: %m", old_mount_path);
 
4064
                }
 
4065
            }
 
4066
        }
 
4067
 
 
4068
      g_free (old_mount_path);
 
4069
 
 
4070
    }
 
4071
 
 
4072
 out:
 
4073
  g_list_foreach (mounts, (GFunc) g_object_unref, NULL);
 
4074
  g_list_free (mounts);
 
4075
 
 
4076
  return TRUE;
 
4077
}
 
4078
 
 
4079
/* ---------------------------------------------------------------------------------------------------- */
 
4080
 
 
4081
/* device_is_media_change_detected, device_is_media_change_detection_* properties */
 
4082
static gboolean
 
4083
update_info_media_detection (Device *device)
 
4084
{
 
4085
  gboolean detected;
 
4086
  gboolean polling;
 
4087
  gboolean inhibitable;
 
4088
  gboolean inhibited;
 
4089
 
 
4090
  detected = FALSE;
 
4091
  polling = FALSE;
 
4092
  inhibitable = FALSE;
 
4093
  inhibited = FALSE;
 
4094
 
 
4095
  if (device->priv->device_is_removable)
 
4096
    {
 
4097
      guint64 evt_media_change;
 
4098
      GUdevDevice *parent;
 
4099
 
 
4100
      evt_media_change = sysfs_get_uint64 (device->priv->native_path, "../../evt_media_change");
 
4101
      if (evt_media_change & 1)
 
4102
        {
 
4103
          /* SATA AN capabable drive */
 
4104
 
 
4105
          polling = FALSE;
 
4106
          detected = TRUE;
 
4107
          goto determined;
 
4108
        }
 
4109
 
 
4110
      parent = g_udev_device_get_parent_with_subsystem (device->priv->d, "platform", NULL);
 
4111
      if (parent != NULL)
 
4112
        {
 
4113
          /* never poll PC floppy drives, they are noisy (fdo #22149) */
 
4114
          if (g_str_has_prefix (g_udev_device_get_name (parent), "floppy."))
 
4115
            {
 
4116
              g_object_unref (parent);
 
4117
              goto determined;
 
4118
            }
 
4119
          g_object_unref (parent);
 
4120
        }
 
4121
 
 
4122
      /* assume the device needs polling */
 
4123
      polling = TRUE;
 
4124
      inhibitable = TRUE;
 
4125
 
 
4126
      /* custom udev rules might want to disable polling for known-broken
 
4127
       * devices (fdo #26508) */
 
4128
      if (g_udev_device_has_property (device->priv->d, "UDISKS_DISABLE_POLLING") &&
 
4129
          g_udev_device_get_property_as_boolean (device->priv->d, "UDISKS_DISABLE_POLLING"))
 
4130
        polling = FALSE;
 
4131
 
 
4132
      if (device->priv->polling_inhibitors != NULL || daemon_local_has_polling_inhibitors (device->priv->daemon))
 
4133
        {
 
4134
 
 
4135
          detected = FALSE;
 
4136
          inhibited = TRUE;
 
4137
        }
 
4138
      else
 
4139
        {
 
4140
          detected = TRUE;
 
4141
          inhibited = FALSE;
 
4142
        }
 
4143
    }
 
4144
 
 
4145
 determined:
 
4146
  device_set_device_is_media_change_detected (device, detected);
 
4147
  device_set_device_is_media_change_detection_polling (device, polling);
 
4148
  device_set_device_is_media_change_detection_inhibitable (device, inhibitable);
 
4149
  device_set_device_is_media_change_detection_inhibited (device, inhibited);
 
4150
 
 
4151
  return TRUE;
 
4152
}
 
4153
 
 
4154
/* ---------------------------------------------------------------------------------------------------- */
 
4155
 
 
4156
/* drive_adapter property */
 
4157
static gboolean
 
4158
update_info_drive_adapter (Device *device)
 
4159
{
 
4160
  Adapter *adapter;
 
4161
  const gchar *adapter_object_path;
 
4162
 
 
4163
  adapter_object_path = NULL;
 
4164
 
 
4165
  adapter = daemon_local_find_enclosing_adapter (device->priv->daemon, device->priv->native_path);
 
4166
  if (adapter != NULL)
 
4167
    {
 
4168
      adapter_object_path = adapter_local_get_object_path (adapter);
 
4169
    }
 
4170
 
 
4171
  device_set_drive_adapter (device, adapter_object_path);
 
4172
 
 
4173
  return TRUE;
 
4174
}
 
4175
 
 
4176
/* drive_ports property */
 
4177
static gboolean
 
4178
update_info_drive_ports (Device *device)
 
4179
{
 
4180
  GList *ports;
 
4181
  GList *l;
 
4182
  GPtrArray *p;
 
4183
 
 
4184
  ports = daemon_local_find_enclosing_ports (device->priv->daemon, device->priv->native_path);
 
4185
 
 
4186
  p = g_ptr_array_new ();
 
4187
  for (l = ports; l != NULL; l = l->next)
 
4188
    {
 
4189
      Port *port = PORT (l->data);
 
4190
 
 
4191
      g_ptr_array_add (p, (gpointer) port_local_get_object_path (port));
 
4192
    }
 
4193
  g_ptr_array_add (p, NULL);
 
4194
  device_set_drive_ports (device, (GStrv) p->pdata);
 
4195
  g_ptr_array_unref (p);
 
4196
 
 
4197
  g_list_free (ports);
 
4198
 
 
4199
  return TRUE;
 
4200
}
 
4201
 
 
4202
/* drive_similar_devices property */
 
4203
static gboolean
 
4204
update_info_drive_similar_devices (Device *device)
 
4205
{
 
4206
  GList *devices;
 
4207
  GList *l;
 
4208
  GPtrArray *p;
 
4209
 
 
4210
  p = g_ptr_array_new ();
 
4211
 
 
4212
  if (!device->priv->device_is_drive)
 
4213
    goto out;
 
4214
 
 
4215
  /* We need non-empty SERIAL and WWN for this to work */
 
4216
  if ((device->priv->drive_serial == NULL || strlen (device->priv->drive_serial) == 0) ||
 
4217
      (device->priv->drive_wwn == NULL || strlen (device->priv->drive_wwn) == 0))
 
4218
    goto out;
 
4219
 
 
4220
  /* TODO: this might be slow - if so, use a hash on the Daemon class */
 
4221
  devices = daemon_local_get_all_devices (device->priv->daemon);
 
4222
  for (l = devices; l != NULL; l = l->next)
 
4223
    {
 
4224
      Device *d = DEVICE (l->data);
 
4225
 
 
4226
      if (!d->priv->device_is_drive)
 
4227
        continue;
 
4228
 
 
4229
      if (d == device)
 
4230
        continue;
 
4231
 
 
4232
#if 0
 
4233
      g_debug ("looking at %s:\n"
 
4234
               "  %s\n"
 
4235
               "  %s\n"
 
4236
               "    %s\n"
 
4237
               "    %s\n",
 
4238
               d->priv->device_file,
 
4239
               d->priv->drive_serial,
 
4240
               device->priv->drive_serial,
 
4241
               d->priv->drive_wwn,
 
4242
               device->priv->drive_wwn);
 
4243
#endif
 
4244
 
 
4245
      /* current policy is that *both* SERIAL and WWN must match */
 
4246
      if (g_strcmp0 (d->priv->drive_serial, device->priv->drive_serial) == 0 &&
 
4247
          g_strcmp0 (d->priv->drive_wwn, device->priv->drive_wwn) == 0)
 
4248
        {
 
4249
          g_ptr_array_add (p, d->priv->object_path);
 
4250
 
 
4251
          /* ensure that the device we added also exists in its own drive_similar_devices property */
 
4252
          if (!ptr_array_has_string (d->priv->drive_similar_devices, device->priv->object_path))
 
4253
            {
 
4254
              //g_debug ("\n************************************************************\nforcing update in idle");
 
4255
              update_info_in_idle (d);
 
4256
            }
 
4257
          else
 
4258
            {
 
4259
              //g_debug ("\n************************************************************\nNOT forcing update in idle");
 
4260
            }
 
4261
        }
 
4262
    }
 
4263
 
 
4264
 out:
 
4265
  g_ptr_array_add (p, NULL);
 
4266
  device_set_drive_similar_devices (device, (GStrv) p->pdata);
 
4267
  g_ptr_array_free (p, TRUE);
 
4268
  return TRUE;
 
4269
}
 
4270
 
 
4271
/* ---------------------------------------------------------------------------------------------------- */
 
4272
 
 
4273
/* update device_is_linux_loop and linux_loop_* properties */
 
4274
static gboolean
 
4275
update_info_linux_loop (Device *device)
 
4276
{
 
4277
  gboolean ret;
 
4278
  gint fd;
 
4279
  struct loop_info64 loop_info_buf;
 
4280
  gboolean is_loop;
 
4281
  gchar *s;
 
4282
  gchar *s2;
 
4283
 
 
4284
  is_loop = FALSE;
 
4285
  ret = FALSE;
 
4286
  fd = -1;
 
4287
 
 
4288
  if (!g_str_has_prefix (device->priv->native_path, "/sys/devices/virtual/block/loop"))
 
4289
    {
 
4290
      ret = TRUE;
 
4291
      goto out;
 
4292
    }
 
4293
 
 
4294
  fd = open (device->priv->device_file, O_RDONLY);
 
4295
  if (fd < 0)
 
4296
    goto out;
 
4297
 
 
4298
  if (ioctl (fd, LOOP_GET_STATUS64, &loop_info_buf) != 0)
 
4299
    goto out;
 
4300
 
 
4301
  /* TODO: is lo_file_name really NUL-terminated? */
 
4302
  device_set_linux_loop_filename (device, (const gchar *) loop_info_buf.lo_file_name);
 
4303
 
 
4304
  ret = TRUE;
 
4305
  is_loop = TRUE;
 
4306
 
 
4307
  device_set_drive_vendor (device, "Linux");
 
4308
  s2 = g_path_get_basename ((gchar *) loop_info_buf.lo_file_name);
 
4309
  s = g_strdup_printf ("Loop: %s", s2);
 
4310
  g_free (s2);
 
4311
  device_set_drive_model (device, s);
 
4312
  g_free (s);
 
4313
 
 
4314
 out:
 
4315
  if (fd > 0)
 
4316
    close (fd);
 
4317
  device_set_device_is_linux_loop (device, is_loop);
 
4318
  return ret;
 
4319
}
 
4320
 
 
4321
/* ---------------------------------------------------------------------------------------------------- */
 
4322
 
 
4323
typedef struct
 
4324
{
 
4325
  guint idle_id;
 
4326
  Device *device;
 
4327
} UpdateInfoInIdleData;
 
4328
 
 
4329
static void
 
4330
update_info_in_idle_device_unreffed (gpointer user_data,
 
4331
                                     GObject *where_the_object_was)
 
4332
{
 
4333
  UpdateInfoInIdleData *data = user_data;
 
4334
  g_source_remove (data->idle_id);
 
4335
}
 
4336
 
 
4337
static void
 
4338
update_info_in_idle_data_free (UpdateInfoInIdleData *data)
 
4339
{
 
4340
  g_object_weak_unref (G_OBJECT (data->device), update_info_in_idle_device_unreffed, data);
 
4341
  g_free (data);
 
4342
}
 
4343
 
 
4344
static gboolean
 
4345
update_info_in_idle_cb (gpointer user_data)
 
4346
{
 
4347
  UpdateInfoInIdleData *data = user_data;
 
4348
 
 
4349
  /* this indirectly calls update_info and also removes the device
 
4350
   * if it wants to be removed (e.g. if update_info() returns FALSE)
 
4351
   */
 
4352
  daemon_local_synthesize_changed (data->device->priv->daemon, data->device);
 
4353
 
 
4354
  return FALSE; /* remove source */
 
4355
}
 
4356
 
 
4357
/**
 
4358
 * update_info_in_idle:
 
4359
 * @device: A #Device.
 
4360
 *
 
4361
 * Like update_info() but does the update in idle. Takes a weak ref to
 
4362
 * @device and cancels the update if @device is unreffed.
 
4363
 */
 
4364
static void
 
4365
update_info_in_idle (Device *device)
 
4366
{
 
4367
  UpdateInfoInIdleData *data;
 
4368
 
 
4369
  data = g_new0 (UpdateInfoInIdleData, 1);
 
4370
  data->device = device;
 
4371
  data->idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
 
4372
                                   update_info_in_idle_cb,
 
4373
                                   data,
 
4374
                                   (GDestroyNotify) update_info_in_idle_data_free);
 
4375
 
 
4376
  g_object_weak_ref (G_OBJECT (device), update_info_in_idle_device_unreffed, data);
 
4377
}
 
4378
 
 
4379
/**
 
4380
 * update_info:
 
4381
 * @device: the device
 
4382
 *
 
4383
 * Update information about the device.
 
4384
 *
 
4385
 * If one or more properties changed, the changes are scheduled to be emitted. Use
 
4386
 * drain_pending_changes() to force emitting the pending changes (which is useful
 
4387
 * before returning the result of an operation).
 
4388
 *
 
4389
 * Returns: #TRUE to keep (or add) the device; #FALSE to ignore (or remove) the device
 
4390
 **/
 
4391
static gboolean
 
4392
update_info (Device *device)
 
4393
{
 
4394
  char *s;
 
4395
  guint n;
 
4396
  gboolean ret;
 
4397
  char *path;
 
4398
  GDir *dir;
 
4399
  const char *name;
 
4400
  GList *l;
 
4401
  GList *old_slaves_objpath;
 
4402
  GList *old_holders_objpath;
 
4403
  GList *cur_slaves_objpath;
 
4404
  GList *cur_holders_objpath;
 
4405
  GList *added_objpath;
 
4406
  GList *removed_objpath;
 
4407
  GPtrArray *symlinks_by_id;
 
4408
  GPtrArray *symlinks_by_path;
 
4409
  GPtrArray *slaves;
 
4410
  GPtrArray *holders;
 
4411
  gint major;
 
4412
  gint minor;
 
4413
  gboolean media_available;
 
4414
 
 
4415
  ret = FALSE;
 
4416
 
 
4417
  PROFILE ("update_info(device=%s) start", device->priv->native_path);
 
4418
 
 
4419
  g_print ("**** UPDATING %s\n", device->priv->native_path);
 
4420
 
 
4421
  /* need the slaves/holders to synthesize 'change' events if a device goes away (since the kernel
 
4422
   * doesn't do generate these)
 
4423
   */
 
4424
  old_slaves_objpath = dup_list_from_ptrarray (device->priv->slaves_objpath);
 
4425
  old_holders_objpath = dup_list_from_ptrarray (device->priv->holders_objpath);
 
4426
 
 
4427
  /* drive identification */
 
4428
  if (sysfs_file_exists (device->priv->native_path, "range"))
 
4429
    {
 
4430
      device_set_device_is_drive (device, TRUE);
 
4431
    }
 
4432
  else
 
4433
    {
 
4434
      device_set_device_is_drive (device, FALSE);
 
4435
    }
 
4436
 
 
4437
  if (!g_udev_device_has_property (device->priv->d, "MAJOR") || !g_udev_device_has_property (device->priv->d, "MINOR"))
 
4438
    {
 
4439
      g_warning ("No major/minor for %s", device->priv->native_path);
 
4440
      goto out;
 
4441
    }
 
4442
 
 
4443
  /* ignore dm devices that are suspended */
 
4444
  if (g_str_has_prefix (g_udev_device_get_name (device->priv->d), "dm-"))
 
4445
    {
 
4446
      if (g_strcmp0 (g_udev_device_get_property (device->priv->d, "DM_SUSPENDED"), "1") == 0)
 
4447
        goto out;
 
4448
    }
 
4449
 
 
4450
  major = g_udev_device_get_property_as_int (device->priv->d, "MAJOR");
 
4451
  minor = g_udev_device_get_property_as_int (device->priv->d, "MINOR");
 
4452
  device->priv->dev = makedev (major, minor);
 
4453
 
 
4454
  device_set_device_file (device, g_udev_device_get_device_file (device->priv->d));
 
4455
  if (device->priv->device_file == NULL)
 
4456
    {
 
4457
      g_warning ("No device file for %s", device->priv->native_path);
 
4458
      goto out;
 
4459
    }
 
4460
 
 
4461
  const char * const * symlinks;
 
4462
  symlinks = g_udev_device_get_device_file_symlinks (device->priv->d);
 
4463
  symlinks_by_id = g_ptr_array_new ();
 
4464
  symlinks_by_path = g_ptr_array_new ();
 
4465
  for (n = 0; symlinks[n] != NULL; n++)
 
4466
    {
 
4467
      if (g_str_has_prefix (symlinks[n], "/dev/disk/by-id/") || g_str_has_prefix (symlinks[n], "/dev/disk/by-uuid/"))
 
4468
        {
 
4469
          g_ptr_array_add (symlinks_by_id, (gpointer) symlinks[n]);
 
4470
        }
 
4471
      else if (g_str_has_prefix (symlinks[n], "/dev/disk/by-path/"))
 
4472
        {
 
4473
          g_ptr_array_add (symlinks_by_path, (gpointer) symlinks[n]);
 
4474
        }
 
4475
    }
 
4476
  g_ptr_array_sort (symlinks_by_id, (GCompareFunc) ptr_str_array_compare);
 
4477
  g_ptr_array_sort (symlinks_by_path, (GCompareFunc) ptr_str_array_compare);
 
4478
  g_ptr_array_add (symlinks_by_id, NULL);
 
4479
  g_ptr_array_add (symlinks_by_path, NULL);
 
4480
  device_set_device_file_by_id (device, (GStrv) symlinks_by_id->pdata);
 
4481
  device_set_device_file_by_path (device, (GStrv) symlinks_by_path->pdata);
 
4482
  g_ptr_array_free (symlinks_by_id, TRUE);
 
4483
  g_ptr_array_free (symlinks_by_path, TRUE);
 
4484
 
 
4485
  device_set_device_is_removable (device, (sysfs_get_int (device->priv->native_path, "removable") != 0));
 
4486
 
 
4487
  /* device_is_media_available and device_media_detection_time property */
 
4488
  if (device->priv->device_is_removable)
 
4489
    {
 
4490
      media_available = FALSE;
 
4491
 
 
4492
      if (!g_udev_device_get_property_as_boolean (device->priv->d, "ID_CDROM") &&
 
4493
          !g_udev_device_get_property_as_boolean (device->priv->d, "ID_DRIVE_FLOPPY"))
 
4494
        {
 
4495
          int fd;
 
4496
          fd = open (device->priv->device_file, O_RDONLY);
 
4497
          if (fd >= 0)
 
4498
            {
 
4499
              media_available = TRUE;
 
4500
              close (fd);
 
4501
            }
 
4502
        }
 
4503
      else
 
4504
        {
 
4505
          if (g_udev_device_get_property_as_boolean (device->priv->d, "ID_CDROM_MEDIA"))
 
4506
            {
 
4507
              media_available = TRUE;
 
4508
            }
 
4509
          else
 
4510
            {
 
4511
              media_available = FALSE;
 
4512
            }
 
4513
        }
 
4514
    }
 
4515
  else
 
4516
    {
 
4517
      media_available = TRUE;
 
4518
    }
 
4519
  device_set_device_is_media_available (device, media_available);
 
4520
  if (media_available)
 
4521
    {
 
4522
      if (device->priv->device_media_detection_time == 0)
 
4523
        device_set_device_media_detection_time (device, (guint64) time (NULL));
 
4524
    }
 
4525
  else
 
4526
    {
 
4527
      device_set_device_media_detection_time (device, 0);
 
4528
    }
 
4529
 
 
4530
  /* device_size, device_block_size and device_is_read_only properties */
 
4531
  if (device->priv->device_is_media_available)
 
4532
    {
 
4533
      guint64 block_size;
 
4534
 
 
4535
      device_set_device_size (device, sysfs_get_uint64 (device->priv->native_path, "size") * ((guint64) 512));
 
4536
      device_set_device_is_read_only (device, (sysfs_get_int (device->priv->native_path, "ro") != 0));
 
4537
      /* This is not available on all devices so fall back to 512 if unavailable.
 
4538
       *
 
4539
       * Another way to get this information is the BLKSSZGET ioctl but we don't want
 
4540
       * to open the device. Ideally vol_id would export it.
 
4541
       */
 
4542
      block_size = sysfs_get_uint64 (device->priv->native_path, "queue/hw_sector_size");
 
4543
      if (block_size == 0)
 
4544
        block_size = 512;
 
4545
      device_set_device_block_size (device, block_size);
 
4546
 
 
4547
    }
 
4548
  else
 
4549
    {
 
4550
      device_set_device_size (device, 0);
 
4551
      device_set_device_block_size (device, 0);
 
4552
      device_set_device_is_read_only (device, FALSE);
 
4553
    }
 
4554
 
 
4555
  /* Maintain (non-exported) properties holders and slaves for the holders resp. slaves
 
4556
   * directories in sysfs. The entries in these arrays are object paths - we ignore
 
4557
   * an entry unless it corresponds to an device in our local database.
 
4558
   */
 
4559
  path = g_build_filename (device->priv->native_path, "slaves", NULL);
 
4560
  slaves = g_ptr_array_new ();
 
4561
  if ((dir = g_dir_open (path, 0, NULL)) != NULL)
 
4562
    {
 
4563
      while ((name = g_dir_read_name (dir)) != NULL)
 
4564
        {
 
4565
          Device *device2;
 
4566
 
 
4567
          s = compute_object_path (name);
 
4568
 
 
4569
          device2 = daemon_local_find_by_object_path (device->priv->daemon, s);
 
4570
          if (device2 != NULL)
 
4571
            {
 
4572
              //g_debug ("%s has slave %s", device->priv->object_path, s);
 
4573
              g_ptr_array_add (slaves, s);
 
4574
            }
 
4575
          else
 
4576
            {
 
4577
              //g_debug ("%s has non-existant slave %s", device->priv->object_path, s);
 
4578
              g_free (s);
 
4579
            }
 
4580
        }
 
4581
      g_dir_close (dir);
 
4582
    }
 
4583
  g_free (path);
 
4584
  g_ptr_array_sort (slaves, (GCompareFunc) ptr_str_array_compare);
 
4585
  g_ptr_array_add (slaves, NULL);
 
4586
  device_set_slaves_objpath (device, (GStrv) slaves->pdata);
 
4587
  g_ptr_array_foreach (slaves, (GFunc) g_free, NULL);
 
4588
  g_ptr_array_free (slaves, TRUE);
 
4589
 
 
4590
  path = g_build_filename (device->priv->native_path, "holders", NULL);
 
4591
  holders = g_ptr_array_new ();
 
4592
  if ((dir = g_dir_open (path, 0, NULL)) != NULL)
 
4593
    {
 
4594
      while ((name = g_dir_read_name (dir)) != NULL)
 
4595
        {
 
4596
          Device *device2;
 
4597
 
 
4598
          s = compute_object_path (name);
 
4599
          device2 = daemon_local_find_by_object_path (device->priv->daemon, s);
 
4600
          if (device2 != NULL)
 
4601
            {
 
4602
              //g_debug ("%s has holder %s", device->priv->object_path, s);
 
4603
              g_ptr_array_add (holders, s);
 
4604
            }
 
4605
          else
 
4606
            {
 
4607
              //g_debug ("%s has non-existant holder %s", device->priv->object_path, s);
 
4608
              g_free (s);
 
4609
            }
 
4610
        }
 
4611
      g_dir_close (dir);
 
4612
    }
 
4613
  g_free (path);
 
4614
  g_ptr_array_sort (holders, (GCompareFunc) ptr_str_array_compare);
 
4615
  g_ptr_array_add (holders, NULL);
 
4616
  device_set_holders_objpath (device, (GStrv) holders->pdata);
 
4617
  g_ptr_array_foreach (holders, (GFunc) g_free, NULL);
 
4618
  g_ptr_array_free (holders, TRUE);
 
4619
 
 
4620
  /* ------------------------------------- */
 
4621
  /* Now set all properties from udev data */
 
4622
  /* ------------------------------------- */
 
4623
 
 
4624
  /* at this point we have
 
4625
   *
 
4626
   *  - device_file
 
4627
   *  - device_file_by_id
 
4628
   *  - device_file_by_path
 
4629
   *  - device_size
 
4630
   *  - device_block_size
 
4631
   *  - device_is_removable
 
4632
   *  - device_is_read_only
 
4633
   *  - device_is_drive
 
4634
   *  - device_is_media_available
 
4635
   *  - device_is_partition
 
4636
   *  - device_is_partition_table
 
4637
   *  - slaves_objpath
 
4638
   *  - holders_objpath
 
4639
   *
 
4640
   *  - partition_number
 
4641
   *  - partition_slave
 
4642
   *
 
4643
   */
 
4644
 
 
4645
  /* device_is_linux_loop and linux_loop_* properties */
 
4646
  if (!update_info_linux_loop (device))
 
4647
    goto out;
 
4648
 
 
4649
  /* partition_* properties */
 
4650
  if (!update_info_partition (device))
 
4651
    goto out;
 
4652
 
 
4653
  /* partition_table_* properties */
 
4654
  if (!update_info_partition_table (device))
 
4655
    goto out;
 
4656
 
 
4657
  /* device_presentation_hide, device_presentation_name and device_presentation_icon_name properties */
 
4658
  if (!update_info_presentation (device))
 
4659
    goto out;
 
4660
 
 
4661
  /* id_* properties */
 
4662
  if (!update_info_id (device))
 
4663
    goto out;
 
4664
 
 
4665
  /* drive_* properties */
 
4666
  if (!update_info_drive (device))
 
4667
    goto out;
 
4668
 
 
4669
  /* device_is_optical_disc and optical_disc_* properties */
 
4670
  if (!update_info_optical_disc (device))
 
4671
    goto out;
 
4672
 
 
4673
  /* device_is_luks and luks_holder */
 
4674
  if (!update_info_luks (device))
 
4675
    goto out;
 
4676
 
 
4677
  /* device_is_luks_cleartext and luks_cleartext_* properties */
 
4678
  if (!update_info_luks_cleartext (device))
 
4679
    goto out;
 
4680
 
 
4681
#ifdef HAVE_LVM2
 
4682
  /* device_is_linux_lvm2_lv and linux_lvm2_lv_* properties */
 
4683
  if (!update_info_linux_lvm2_lv (device))
 
4684
    goto out;
 
4685
 
 
4686
  /* device_is_linux_lvm2_pv and linux_lvm2_pv_* properties */
 
4687
  if (!update_info_linux_lvm2_pv (device))
 
4688
    goto out;
 
4689
#endif
 
4690
 
 
4691
#ifdef HAVE_DMMP
 
4692
  /* device_is_linux_dmmp and linux_dmmp_* properties */
 
4693
  if (!update_info_linux_dmmp (device))
 
4694
    goto out;
 
4695
 
 
4696
  /* device_is_partition and partition_* properties for dm-0 "partitions" on a multi-path device  */
 
4697
  if (!update_info_partition_on_linux_dmmp (device))
 
4698
    goto out;
 
4699
 
 
4700
  /* device_is_linux_dmmp_component and linux_dmmp_component_* properties */
 
4701
  if (!update_info_linux_dmmp_component (device))
 
4702
    goto out;
 
4703
#endif
 
4704
 
 
4705
  /* device_is_linux_md_component and linux_md_component_* properties */
 
4706
  if (!update_info_linux_md_component (device))
 
4707
    goto out;
 
4708
 
 
4709
  /* device_is_linux_md and linux_md_* properties */
 
4710
  if (!update_info_linux_md (device))
 
4711
    goto out;
 
4712
 
 
4713
  /* drive_ata_smart_* properties */
 
4714
  if (!update_info_drive_ata_smart (device))
 
4715
    goto out;
 
4716
 
 
4717
  /* drive_can_spindown property */
 
4718
  if (!update_info_drive_can_spindown (device))
 
4719
    goto out;
 
4720
 
 
4721
  /* device_is_system_internal property */
 
4722
  if (!update_info_is_system_internal (device))
 
4723
    goto out;
 
4724
 
 
4725
  /* device_is_mounted, device_mount, device_mounted_by_uid */
 
4726
  if (!update_info_mount_state (device))
 
4727
    goto out;
 
4728
 
 
4729
  /* device_is_media_change_detected, device_is_media_change_detection_* properties */
 
4730
  if (!update_info_media_detection (device))
 
4731
    goto out;
 
4732
 
 
4733
  /* drive_adapter proprety */
 
4734
  if (!update_info_drive_adapter (device))
 
4735
    goto out;
 
4736
 
 
4737
  /* drive_ports property */
 
4738
  if (!update_info_drive_ports (device))
 
4739
    goto out;
 
4740
 
 
4741
  /* drive_similar_devices property */
 
4742
  if (!update_info_drive_similar_devices (device))
 
4743
    goto out;
 
4744
 
 
4745
  ret = TRUE;
 
4746
 
 
4747
 out:
 
4748
 
 
4749
  /* Now check if holders/ or slaves/ has changed since last update. We compute
 
4750
   * the delta and do update_info() on each holder/slave that has been
 
4751
   * added/removed.
 
4752
   *
 
4753
   * Note that this won't trigger an endless loop since we look at the diffs.
 
4754
   *
 
4755
   * We have to do this because the kernel doesn't generate any 'change' event
 
4756
   * when slaves/ or holders/ change. This is unfortunate because we *need* such
 
4757
   * a change event to update properties devices (for example: luks_holder).
 
4758
   *
 
4759
   * We do the update in idle because the update may depend on the device
 
4760
   * currently being processed being added.
 
4761
   */
 
4762
 
 
4763
  cur_slaves_objpath = dup_list_from_ptrarray (device->priv->slaves_objpath);
 
4764
  cur_holders_objpath = dup_list_from_ptrarray (device->priv->holders_objpath);
 
4765
 
 
4766
  old_slaves_objpath = g_list_sort (old_slaves_objpath, (GCompareFunc) g_strcmp0);
 
4767
  old_holders_objpath = g_list_sort (old_holders_objpath, (GCompareFunc) g_strcmp0);
 
4768
  cur_slaves_objpath = g_list_sort (cur_slaves_objpath, (GCompareFunc) g_strcmp0);
 
4769
  cur_holders_objpath = g_list_sort (cur_holders_objpath, (GCompareFunc) g_strcmp0);
 
4770
 
 
4771
  diff_sorted_lists (old_slaves_objpath, cur_slaves_objpath, (GCompareFunc) g_strcmp0, &added_objpath, &removed_objpath);
 
4772
  for (l = added_objpath; l != NULL; l = l->next)
 
4773
    {
 
4774
      const gchar *objpath2 = l->data;
 
4775
      Device *device2;
 
4776
 
 
4777
      //g_debug ("### %s added slave %s", device->priv->object_path, objpath2);
 
4778
      device2 = daemon_local_find_by_object_path (device->priv->daemon, objpath2);
 
4779
      if (device2 != NULL)
 
4780
        {
 
4781
          update_info_in_idle (device2);
 
4782
        }
 
4783
      else
 
4784
        {
 
4785
          g_print ("**** NOTE: %s added non-existant slave %s\n", device->priv->object_path, objpath2);
 
4786
        }
 
4787
    }
 
4788
  for (l = removed_objpath; l != NULL; l = l->next)
 
4789
    {
 
4790
      const gchar *objpath2 = l->data;
 
4791
      Device *device2;
 
4792
 
 
4793
      //g_debug ("### %s removed slave %s", device->priv->object_path, objpath2);
 
4794
      device2 = daemon_local_find_by_object_path (device->priv->daemon, objpath2);
 
4795
      if (device2 != NULL)
 
4796
        {
 
4797
          update_info_in_idle (device2);
 
4798
        }
 
4799
      else
 
4800
        {
 
4801
          //g_debug ("### %s removed non-existant slave %s", device->priv->object_path, objpath2);
 
4802
        }
 
4803
    }
 
4804
  g_list_free (added_objpath);
 
4805
  g_list_free (removed_objpath);
 
4806
 
 
4807
  diff_sorted_lists (old_holders_objpath,
 
4808
                     cur_holders_objpath,
 
4809
                     (GCompareFunc) g_strcmp0,
 
4810
                     &added_objpath,
 
4811
                     &removed_objpath);
 
4812
  for (l = added_objpath; l != NULL; l = l->next)
 
4813
    {
 
4814
      const gchar *objpath2 = l->data;
 
4815
      Device *device2;
 
4816
 
 
4817
      //g_debug ("### %s added holder %s", device->priv->object_path, objpath2);
 
4818
      device2 = daemon_local_find_by_object_path (device->priv->daemon, objpath2);
 
4819
      if (device2 != NULL)
 
4820
        {
 
4821
          update_info_in_idle (device2);
 
4822
        }
 
4823
      else
 
4824
        {
 
4825
          g_print ("**** NOTE: %s added non-existant holder %s\n", device->priv->object_path, objpath2);
 
4826
        }
 
4827
    }
 
4828
  for (l = removed_objpath; l != NULL; l = l->next)
 
4829
    {
 
4830
      const gchar *objpath2 = l->data;
 
4831
      Device *device2;
 
4832
 
 
4833
      //g_debug ("### %s removed holder %s", device->priv->object_path, objpath2);
 
4834
      device2 = daemon_local_find_by_object_path (device->priv->daemon, objpath2);
 
4835
      if (device2 != NULL)
 
4836
        {
 
4837
          update_info_in_idle (device2);
 
4838
        }
 
4839
      else
 
4840
        {
 
4841
          //g_debug ("### %s removed non-existant holder %s", device->priv->object_path, objpath2);
 
4842
        }
 
4843
    }
 
4844
  g_list_free (added_objpath);
 
4845
  g_list_free (removed_objpath);
 
4846
 
 
4847
  g_list_foreach (old_slaves_objpath, (GFunc) g_free, NULL);
 
4848
  g_list_free (old_slaves_objpath);
 
4849
  g_list_foreach (old_holders_objpath, (GFunc) g_free, NULL);
 
4850
  g_list_free (old_holders_objpath);
 
4851
  g_list_foreach (cur_slaves_objpath, (GFunc) g_free, NULL);
 
4852
  g_list_free (cur_slaves_objpath);
 
4853
  g_list_foreach (cur_holders_objpath, (GFunc) g_free, NULL);
 
4854
  g_list_free (cur_holders_objpath);
 
4855
 
 
4856
  PROFILE ("update_info(device=%s) end", device->priv->native_path);
 
4857
  return ret;
 
4858
}
 
4859
 
 
4860
/**
 
4861
 * device_local_is_busy:
 
4862
 * @device: A #Device.
 
4863
 * @check_partitions: Whether to check if partitions is busy if @device is a partition table
 
4864
 * @check_mounted: Whether to check if device has mounted file systems
 
4865
 * @error: Either %NULL or a #GError to set to #ERROR_BUSY and an appropriate
 
4866
 * message, e.g. "Device is busy" or "A partition on the device is busy" if the device is busy.
 
4867
 *
 
4868
 * Checks if @device is busy.
 
4869
 *
 
4870
 * Returns: %TRUE if the device or, if @check_partitions is %TRUE, a partition on the device is busy.
 
4871
 */
 
4872
static gboolean
 
4873
device_local_is_busy (Device *device,
 
4874
                      gboolean check_partitions,
 
4875
                      gboolean check_mounted,
 
4876
                      GError **error)
 
4877
{
 
4878
  gboolean ret;
 
4879
 
 
4880
  ret = TRUE;
 
4881
 
 
4882
  /* busy if a job is pending */
 
4883
  if (device->priv->job != NULL)
 
4884
    {
 
4885
      g_set_error (error, ERROR, ERROR_BUSY, "A job is pending on %s", device->priv->device_file);
 
4886
      goto out;
 
4887
    }
 
4888
 
 
4889
  /* or if we're mounted */
 
4890
  if (check_mounted && device->priv->device_is_mounted)
 
4891
    {
 
4892
      g_set_error (error, ERROR, ERROR_BUSY, "%s is mounted", device->priv->device_file);
 
4893
      goto out;
 
4894
    }
 
4895
 
 
4896
  /* or if another block device is using/holding us (e.g. if holders/ is non-empty in sysfs) */
 
4897
  if (device->priv->holders_objpath->len > 0)
 
4898
    {
 
4899
      if (device->priv->device_is_linux_dmmp)
 
4900
        {
 
4901
          /* This is OK */
 
4902
        }
 
4903
      else
 
4904
        {
 
4905
          g_set_error (error,
 
4906
                       ERROR,
 
4907
                       ERROR_BUSY,
 
4908
                       "One or more block devices are holding %s",
 
4909
                       device->priv->device_file);
 
4910
          goto out;
 
4911
        }
 
4912
    }
 
4913
 
 
4914
  /* If we are an extended partition, we are also busy if one or more logical partitions are busy
 
4915
   * even if @check_partitions is FALSE... This is because an extended partition only really is
 
4916
   * a place holder.
 
4917
   */
 
4918
  if (g_strcmp0 (device->priv->partition_scheme, "mbr") == 0 && device->priv->partition_type != NULL)
 
4919
    {
 
4920
      gint partition_type;
 
4921
      partition_type = strtol (device->priv->partition_type, NULL, 0);
 
4922
      if (partition_type == 0x05 || partition_type == 0x0f || partition_type == 0x85)
 
4923
        {
 
4924
          Device *drive_device;
 
4925
          drive_device = daemon_local_find_by_object_path (device->priv->daemon, device->priv->partition_slave);
 
4926
          if (device_local_logical_partitions_are_busy (drive_device))
 
4927
            {
 
4928
              g_set_error (error, ERROR, ERROR_BUSY, "%s is an MS-DOS extended partition and one or more "
 
4929
                           "logical partitions are busy", device->priv->device_file);
 
4930
              goto out;
 
4931
            }
 
4932
        }
 
4933
    }
 
4934
 
 
4935
  /* if we are a partition table, we are busy if one of our partitions are busy */
 
4936
  if (check_partitions && device->priv->device_is_partition_table)
 
4937
    {
 
4938
      if (device_local_partitions_are_busy (device))
 
4939
        {
 
4940
          g_set_error (error, ERROR, ERROR_BUSY, "One or more partitions are busy on %s", device->priv->device_file);
 
4941
          goto out;
 
4942
        }
 
4943
    }
 
4944
 
 
4945
  ret = FALSE;
 
4946
 
 
4947
 out:
 
4948
  return ret;
 
4949
}
 
4950
 
 
4951
/* note: this only checks whether the actual partitions are busy;
 
4952
 * caller will need to check the main device itself too
 
4953
 */
 
4954
static gboolean
 
4955
device_local_partitions_are_busy (Device *device)
 
4956
{
 
4957
  gboolean ret;
 
4958
  GList *l;
 
4959
  GList *devices;
 
4960
 
 
4961
  ret = FALSE;
 
4962
 
 
4963
  devices = daemon_local_get_all_devices (device->priv->daemon);
 
4964
  for (l = devices; l != NULL; l = l->next)
 
4965
    {
 
4966
      Device *d = DEVICE (l->data);
 
4967
 
 
4968
      if (d->priv->device_is_partition && d->priv->partition_slave != NULL && g_strcmp0 (d->priv->partition_slave,
 
4969
                                                                                         device->priv->object_path)
 
4970
          == 0)
 
4971
        {
 
4972
 
 
4973
          if (device_local_is_busy (d, FALSE, TRUE, NULL))
 
4974
            {
 
4975
              ret = TRUE;
 
4976
              break;
 
4977
            }
 
4978
        }
 
4979
    }
 
4980
 
 
4981
  g_list_free (devices);
 
4982
 
 
4983
  return ret;
 
4984
}
 
4985
 
 
4986
static gboolean
 
4987
device_local_logical_partitions_are_busy (Device *device)
 
4988
{
 
4989
  gboolean ret;
 
4990
  GList *l;
 
4991
  GList *devices;
 
4992
 
 
4993
  ret = FALSE;
 
4994
 
 
4995
  devices = daemon_local_get_all_devices (device->priv->daemon);
 
4996
  for (l = devices; l != NULL; l = l->next)
 
4997
    {
 
4998
      Device *d = DEVICE (l->data);
 
4999
 
 
5000
      if (d->priv->device_is_partition && d->priv->partition_slave != NULL && g_strcmp0 (d->priv->partition_slave,
 
5001
                                                                                         device->priv->object_path)
 
5002
          == 0 && g_strcmp0 (d->priv->partition_scheme, "mbr") == 0 && d->priv->partition_number >= 5)
 
5003
        {
 
5004
 
 
5005
          if (device_local_is_busy (d, FALSE, TRUE, NULL))
 
5006
            {
 
5007
              ret = TRUE;
 
5008
              break;
 
5009
            }
 
5010
        }
 
5011
    }
 
5012
 
 
5013
  g_list_free (devices);
 
5014
 
 
5015
  return ret;
 
5016
}
 
5017
 
 
5018
static gboolean
 
5019
device_has_logical_partitions (Device *device)
 
5020
{
 
5021
  gboolean ret;
 
5022
  GList *l;
 
5023
  GList *devices;
 
5024
 
 
5025
  ret = FALSE;
 
5026
 
 
5027
  devices = daemon_local_get_all_devices (device->priv->daemon);
 
5028
  for (l = devices; l != NULL; l = l->next)
 
5029
    {
 
5030
      Device *d = DEVICE (l->data);
 
5031
 
 
5032
      if (d->priv->device_is_partition && d->priv->partition_slave != NULL && g_strcmp0 (d->priv->partition_slave,
 
5033
                                                                                         device->priv->object_path)
 
5034
          == 0 && g_strcmp0 (d->priv->partition_scheme, "mbr") == 0 && d->priv->partition_number >= 5)
 
5035
        {
 
5036
 
 
5037
          ret = TRUE;
 
5038
        }
 
5039
    }
 
5040
 
 
5041
  g_list_free (devices);
 
5042
 
 
5043
  return ret;
 
5044
}
 
5045
 
 
5046
void
 
5047
device_removed (Device *device)
 
5048
{
 
5049
  guint n;
 
5050
 
 
5051
  device->priv->removed = TRUE;
 
5052
 
 
5053
  dbus_g_connection_unregister_g_object (device->priv->system_bus_connection, G_OBJECT (device));
 
5054
  g_assert (dbus_g_connection_lookup_g_object (device->priv->system_bus_connection, device->priv->object_path) == NULL);
 
5055
 
 
5056
  /* device is now removed; update all slaves and holders */
 
5057
  for (n = 0; n < device->priv->slaves_objpath->len; n++)
 
5058
    {
 
5059
      const gchar *objpath2 = ((gchar **) device->priv->slaves_objpath->pdata)[n];
 
5060
      Device *device2;
 
5061
 
 
5062
      device2 = daemon_local_find_by_object_path (device->priv->daemon, objpath2);
 
5063
      if (device2 != NULL)
 
5064
        {
 
5065
          update_info (device2);
 
5066
        }
 
5067
    }
 
5068
  for (n = 0; n < device->priv->holders_objpath->len; n++)
 
5069
    {
 
5070
      const gchar *objpath2 = ((gchar **) device->priv->holders_objpath->pdata)[n];
 
5071
      Device *device2;
 
5072
 
 
5073
      device2 = daemon_local_find_by_object_path (device->priv->daemon, objpath2);
 
5074
      if (device2 != NULL)
 
5075
        {
 
5076
          update_info (device2);
 
5077
        }
 
5078
    }
 
5079
 
 
5080
  /* If the device is busy, we possibly need to clean up if the
 
5081
   * device itself is busy. This includes
 
5082
   *
 
5083
   *  - force unmounting the device and/or all it's partitions
 
5084
   *
 
5085
   *  - tearing down a luks mapping if it's a cleartext device
 
5086
   *    backed by a crypted device
 
5087
   *
 
5088
   * but see force_removal() for details.
 
5089
   *
 
5090
   * This is the normally the path where the enclosing device is
 
5091
   * removed. Compare with device_changed() for the
 
5092
   * other path.
 
5093
   */
 
5094
  force_removal (device, NULL, NULL);
 
5095
}
 
5096
 
 
5097
static gboolean
 
5098
device_initial_ata_smart_refresh (gpointer data)
 
5099
{
 
5100
  Device *device = (Device *) data;
 
5101
  static gchar *ata_smart_refresh_data_options[] = { NULL };
 
5102
 
 
5103
  /* if we are inhibited, try again */
 
5104
  if (daemon_local_is_inhibited (device->priv->daemon))
 
5105
    {
 
5106
      g_print("**** INITIAL ATA SMART POLL for %s: Daemon inhibited, trying again\n", device->priv->device_file);
 
5107
      return TRUE;
 
5108
    }
 
5109
 
 
5110
  /* if the SMART status was manually updated, or the device got removed in the
 
5111
   * meantime, don't bother */
 
5112
  if (device->priv->drive_ata_smart_status == (SkSmartOverall) - 1 &&
 
5113
      !device->priv->removed)
 
5114
    {
 
5115
      g_print("**** INITIAL ATA SMART POLL for %s\n", device->priv->device_file);
 
5116
      device_drive_ata_smart_refresh_data (device, ata_smart_refresh_data_options, NULL);
 
5117
    }
 
5118
 
 
5119
  g_object_unref (device);
 
5120
  return FALSE;
 
5121
}
 
5122
 
 
5123
Device *
 
5124
device_new (Daemon *daemon,
 
5125
            GUdevDevice *d)
 
5126
{
 
5127
  Device *device;
 
5128
  const char *native_path;
 
5129
 
 
5130
  device = NULL;
 
5131
  native_path = g_udev_device_get_sysfs_path (d);
 
5132
 
 
5133
  /* ignore ram devices */
 
5134
  if (g_str_has_prefix (native_path, "/sys/devices/virtual/block/ram"))
 
5135
    goto out;
 
5136
 
 
5137
  PROFILE ("device_new(native_path=%s): start", native_path);
 
5138
 
 
5139
  device = DEVICE (g_object_new (TYPE_DEVICE, NULL));
 
5140
  device->priv->d = g_object_ref (d);
 
5141
  device->priv->daemon = g_object_ref (daemon);
 
5142
  device->priv->native_path = g_strdup (native_path);
 
5143
 
 
5144
  /* TODO: we might want to get this from udev or the kernel... to get the time when the device
 
5145
   *       was initially detected... as opposed to this value which is when the device was detected
 
5146
   *       by our daemon... but this will do for now...
 
5147
   */
 
5148
  device->priv->device_detection_time = (guint64) time (NULL);
 
5149
 
 
5150
  PROFILE ("device_new(native_path=%s): update_info", native_path);
 
5151
  if (!update_info (device))
 
5152
    {
 
5153
      g_object_unref (device);
 
5154
      device = NULL;
 
5155
      goto out;
 
5156
    }
 
5157
 
 
5158
  PROFILE ("device_new(native_path=%s): register_disks_device", native_path);
 
5159
  if (!register_disks_device (DEVICE (device)))
 
5160
    {
 
5161
      g_object_unref (device);
 
5162
      device = NULL;
 
5163
      goto out;
 
5164
    }
 
5165
 
 
5166
  /* if just added, update the smart data if applicable */
 
5167
  if (device->priv->drive_ata_smart_is_available)
 
5168
    {
 
5169
      g_print("**** QUEUEING initial ata smart refresh for %s\n", device->priv->device_file);
 
5170
      g_timeout_add_seconds (30, device_initial_ata_smart_refresh, g_object_ref (device));
 
5171
    }
 
5172
 
 
5173
  PROFILE ("device_new(native_path=%s): end", native_path);
 
5174
 out:
 
5175
  return device;
 
5176
}
 
5177
 
 
5178
static void
 
5179
drain_pending_changes (Device *device,
 
5180
                       gboolean force_update)
 
5181
{
 
5182
  gboolean emit_changed;
 
5183
 
 
5184
  emit_changed = FALSE;
 
5185
 
 
5186
  /* the update-in-idle is set up if, and only if, there are pending changes - so
 
5187
   * we should emit a 'change' event only if it is set up
 
5188
   */
 
5189
  if (device->priv->emit_changed_idle_id != 0)
 
5190
    {
 
5191
      g_source_remove (device->priv->emit_changed_idle_id);
 
5192
      device->priv->emit_changed_idle_id = 0;
 
5193
      emit_changed = TRUE;
 
5194
    }
 
5195
 
 
5196
  if ((!device->priv->removed) && (emit_changed || force_update))
 
5197
    {
 
5198
      if (device->priv->object_path != NULL)
 
5199
        {
 
5200
          g_print ("**** EMITTING CHANGED for %s\n", device->priv->native_path);
 
5201
          g_signal_emit_by_name (device, "changed");
 
5202
          g_signal_emit_by_name (device->priv->daemon, "device-changed", device->priv->object_path);
 
5203
        }
 
5204
    }
 
5205
}
 
5206
 
 
5207
static void
 
5208
emit_job_changed (Device *device)
 
5209
{
 
5210
  drain_pending_changes (device, FALSE);
 
5211
 
 
5212
  if (!device->priv->removed)
 
5213
    {
 
5214
      g_print ("**** EMITTING JOB-CHANGED for %s\n", device->priv->native_path);
 
5215
      g_signal_emit_by_name (device->priv->daemon,
 
5216
                             "device-job-changed",
 
5217
                             device->priv->object_path,
 
5218
                             device->priv->job_in_progress,
 
5219
                             device->priv->job_id,
 
5220
                             device->priv->job_initiated_by_uid,
 
5221
                             device->priv->job_is_cancellable,
 
5222
                             device->priv->job_percentage,
 
5223
                             NULL);
 
5224
      g_signal_emit (device,
 
5225
                     signals[JOB_CHANGED_SIGNAL],
 
5226
                     0,
 
5227
                     device->priv->job_in_progress,
 
5228
                     device->priv->job_id,
 
5229
                     device->priv->job_initiated_by_uid,
 
5230
                     device->priv->job_is_cancellable,
 
5231
                     device->priv->job_percentage);
 
5232
    }
 
5233
}
 
5234
 
 
5235
/* called by the daemon on the 'change' uevent */
 
5236
gboolean
 
5237
device_changed (Device *device,
 
5238
                GUdevDevice *d,
 
5239
                gboolean synthesized)
 
5240
{
 
5241
  gboolean keep_device;
 
5242
 
 
5243
  g_object_unref (device->priv->d);
 
5244
  device->priv->d = g_object_ref (d);
 
5245
 
 
5246
  keep_device = update_info (device);
 
5247
 
 
5248
  /* this 'change' event might prompt us to remove the device */
 
5249
  if (!keep_device)
 
5250
    goto out;
 
5251
 
 
5252
  /* no, it's good .. keep it.. and always force a 'change' signal if the event isn't synthesized */
 
5253
  drain_pending_changes (device, !synthesized);
 
5254
 
 
5255
  /* Check if media was removed. If so, we possibly need to clean up
 
5256
   * if the device itself is busy. This includes
 
5257
   *
 
5258
   *  - force unmounting the device
 
5259
   *
 
5260
   *  - tearing down a luks mapping if it's a cleartext device
 
5261
   *    backed by a crypted device
 
5262
   *
 
5263
   * but see force_removal() for details.
 
5264
   *
 
5265
   * This is the normally the path where the media is removed but the enclosing
 
5266
   * device is still present. Compare with device_removed() for
 
5267
   * the other path.
 
5268
   */
 
5269
  if (!device->priv->device_is_media_available)
 
5270
    {
 
5271
      GList *l;
 
5272
      GList *devices;
 
5273
 
 
5274
      force_removal (device, NULL, NULL);
 
5275
 
 
5276
      /* check all partitions */
 
5277
      devices = daemon_local_get_all_devices (device->priv->daemon);
 
5278
      for (l = devices; l != NULL; l = l->next)
 
5279
        {
 
5280
          Device *d = DEVICE (l->data);
 
5281
 
 
5282
          if (d->priv->device_is_partition && d->priv->partition_slave != NULL && strcmp (d->priv->partition_slave,
 
5283
                                                                                          device->priv->object_path)
 
5284
              == 0)
 
5285
            {
 
5286
 
 
5287
              force_removal (d, NULL, NULL);
 
5288
            }
 
5289
        }
 
5290
 
 
5291
      g_list_free (devices);
 
5292
    }
 
5293
 out:
 
5294
  return keep_device;
 
5295
}
 
5296
 
 
5297
/*--------------------------------------------------------------------------------------------------------------*/
 
5298
 
 
5299
const char *
 
5300
device_local_get_object_path (Device *device)
 
5301
{
 
5302
  return device->priv->object_path;
 
5303
}
 
5304
 
 
5305
const char *
 
5306
device_local_get_native_path (Device *device)
 
5307
{
 
5308
  return device->priv->native_path;
 
5309
}
 
5310
 
 
5311
dev_t
 
5312
device_local_get_dev (Device *device)
 
5313
{
 
5314
  return device->priv->dev;
 
5315
}
 
5316
 
 
5317
const char *
 
5318
device_local_get_device_file (Device *device)
 
5319
{
 
5320
  return device->priv->device_file;
 
5321
}
 
5322
 
 
5323
/*--------------------------------------------------------------------------------------------------------------*/
 
5324
 
 
5325
static gboolean
 
5326
throw_error (DBusGMethodInvocation *context,
 
5327
             int error_code,
 
5328
             const char *format,
 
5329
             ...)
 
5330
{
 
5331
  GError *error;
 
5332
  va_list args;
 
5333
  char *message;
 
5334
 
 
5335
  va_start (args, format);
 
5336
  message = g_strdup_vprintf (format, args);
 
5337
  va_end (args);
 
5338
 
 
5339
  if (context == NULL)
 
5340
    {
 
5341
      g_warning ("%s", message);
 
5342
      return TRUE;
 
5343
    }
 
5344
 
 
5345
  error = g_error_new (ERROR, error_code, "%s", message);
 
5346
  dbus_g_method_return_error (context, error);
 
5347
  g_error_free (error);
 
5348
  g_free (message);
 
5349
  return TRUE;
 
5350
}
 
5351
 
 
5352
/*--------------------------------------------------------------------------------------------------------------*/
 
5353
 
 
5354
typedef void
 
5355
(*JobCompletedFunc) (DBusGMethodInvocation *context,
 
5356
                     Device *device,
 
5357
                     gboolean was_cancelled,
 
5358
                     int status,
 
5359
                     const char *stderr,
 
5360
                     const char *stdout,
 
5361
                     gpointer user_data);
 
5362
 
 
5363
struct Job
 
5364
{
 
5365
  char *job_id;
 
5366
 
 
5367
  Device *device;
 
5368
  DBusGMethodInvocation *context;
 
5369
  JobCompletedFunc job_completed_func;
 
5370
  GPid pid;
 
5371
  gpointer user_data;
 
5372
  GDestroyNotify user_data_destroy_func;
 
5373
  gboolean was_cancelled;
 
5374
  gboolean udev_settle;
 
5375
  int status;
 
5376
 
 
5377
  int stderr_fd;
 
5378
  GIOChannel *error_channel;
 
5379
  guint error_channel_source_id;
 
5380
  GString *error_string;
 
5381
 
 
5382
  int stdout_fd;
 
5383
  GIOChannel *out_channel;
 
5384
  guint out_channel_source_id;
 
5385
  GString *stdout_string;
 
5386
  int stdout_string_cursor;
 
5387
 
 
5388
  char *stdin_str;
 
5389
  char *stdin_cursor;
 
5390
  int stdin_fd;
 
5391
  GIOChannel *in_channel;
 
5392
  guint in_channel_source_id;
 
5393
};
 
5394
 
 
5395
static void
 
5396
job_free (Job *job)
 
5397
{
 
5398
  if (job->user_data_destroy_func != NULL)
 
5399
    job->user_data_destroy_func (job->user_data);
 
5400
  if (job->device != NULL)
 
5401
    g_object_unref (job->device);
 
5402
  if (job->stderr_fd >= 0)
 
5403
    close (job->stderr_fd);
 
5404
  if (job->stdout_fd >= 0)
 
5405
    close (job->stdout_fd);
 
5406
  if (job->stdin_fd >= 0)
 
5407
    {
 
5408
      close (job->stdin_fd);
 
5409
      g_source_remove (job->in_channel_source_id);
 
5410
      g_io_channel_unref (job->in_channel);
 
5411
    }
 
5412
  g_source_remove (job->error_channel_source_id);
 
5413
  g_source_remove (job->out_channel_source_id);
 
5414
  g_io_channel_unref (job->error_channel);
 
5415
  g_io_channel_unref (job->out_channel);
 
5416
  g_string_free (job->error_string, TRUE);
 
5417
  /* scrub stdin (may contain secrets) */
 
5418
  if (job->stdin_str != NULL)
 
5419
    {
 
5420
      memset (job->stdin_str, '\0', strlen (job->stdin_str));
 
5421
    }
 
5422
  g_string_free (job->stdout_string, TRUE);
 
5423
  g_free (job->stdin_str);
 
5424
  g_free (job->job_id);
 
5425
  g_free (job);
 
5426
}
 
5427
 
 
5428
static void
 
5429
job_complete (Job *job)
 
5430
{
 
5431
  if (job->device != NULL && job->job_id != NULL)
 
5432
    {
 
5433
      job->device->priv->job_in_progress = FALSE;
 
5434
      g_free (job->device->priv->job_id);
 
5435
      job->device->priv->job_id = NULL;
 
5436
      job->device->priv->job_initiated_by_uid = 0;
 
5437
      job->device->priv->job_is_cancellable = FALSE;
 
5438
      job->device->priv->job_percentage = -1.0;
 
5439
 
 
5440
      job->device->priv->job = NULL;
 
5441
    }
 
5442
 
 
5443
  job->job_completed_func (job->context,
 
5444
                           job->device,
 
5445
                           job->was_cancelled,
 
5446
                           job->status,
 
5447
                           job->error_string->str,
 
5448
                           job->stdout_string->str,
 
5449
                           job->user_data);
 
5450
 
 
5451
  if (job->device != NULL && job->job_id != NULL)
 
5452
    {
 
5453
      emit_job_changed (job->device);
 
5454
    }
 
5455
 
 
5456
  job_free (job);
 
5457
}
 
5458
 
 
5459
static void
 
5460
job_udevadm_settle_child_cb (GPid pid,
 
5461
                             gint status,
 
5462
                             gpointer user_data)
 
5463
{
 
5464
  Job *job = user_data;
 
5465
  job_complete (job);
 
5466
}
 
5467
 
 
5468
static void
 
5469
job_child_watch_cb (GPid pid,
 
5470
                    int status,
 
5471
                    gpointer user_data)
 
5472
{
 
5473
  char *buf;
 
5474
  gsize buf_size;
 
5475
  Job *job = user_data;
 
5476
 
 
5477
  if (g_io_channel_read_to_end (job->error_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL)
 
5478
    {
 
5479
      g_string_append_len (job->error_string, buf, buf_size);
 
5480
      g_free (buf);
 
5481
    }
 
5482
  if (g_io_channel_read_to_end (job->out_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL)
 
5483
    {
 
5484
      g_string_append_len (job->stdout_string, buf, buf_size);
 
5485
      g_free (buf);
 
5486
    }
 
5487
 
 
5488
  PROFILE ("job finish (id=%s, pid=%i, device=%s)", job->job_id, job->pid, job->device ? job->device->priv->device_file : "none");
 
5489
  g_print ("helper(pid %5d): completed with exit code %d\n", job->pid, WEXITSTATUS (status));
 
5490
 
 
5491
  job->status = status;
 
5492
 
 
5493
  /* if requested, run 'udevadm settle' on success */
 
5494
  if (!job->was_cancelled && WIFEXITED (status) && WEXITSTATUS (status) == 0 && job->udev_settle)
 
5495
    {
 
5496
      GError *error;
 
5497
      gchar *argv[] =
 
5498
        { "udevadm", "settle", "--quiet", NULL };
 
5499
      GPid udevadm_pid;
 
5500
 
 
5501
      error = NULL;
 
5502
      if (!g_spawn_async (NULL,
 
5503
                          argv,
 
5504
                          NULL,
 
5505
                          G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
 
5506
                          NULL,
 
5507
                          NULL,
 
5508
                          &udevadm_pid,
 
5509
                          &error))
 
5510
        {
 
5511
          g_warning ("Error running 'udevadm settle --quiet': %s", error->message);
 
5512
          g_error_free (error);
 
5513
 
 
5514
          job_complete (job);
 
5515
        }
 
5516
      else
 
5517
        {
 
5518
          g_child_watch_add (udevadm_pid, job_udevadm_settle_child_cb, job);
 
5519
        }
 
5520
    }
 
5521
  else
 
5522
    {
 
5523
      /* return immediately on error */
 
5524
      job_complete (job);
 
5525
    }
 
5526
}
 
5527
 
 
5528
static void
 
5529
job_cancel (Device *device)
 
5530
{
 
5531
  g_return_if_fail (device->priv->job != NULL);
 
5532
 
 
5533
  device->priv->job->was_cancelled = TRUE;
 
5534
 
 
5535
  /* TODO: maybe wait and user a bigger hammer? (SIGKILL) */
 
5536
  kill (device->priv->job->pid, SIGTERM);
 
5537
}
 
5538
 
 
5539
static gboolean
 
5540
job_read_error (GIOChannel *channel,
 
5541
                GIOCondition condition,
 
5542
                gpointer user_data)
 
5543
{
 
5544
  char buf[1024];
 
5545
  gsize bytes_read;
 
5546
  Job *job = user_data;
 
5547
 
 
5548
  g_io_channel_read_chars (channel, buf, sizeof buf, &bytes_read, NULL);
 
5549
  g_string_append_len (job->error_string, buf, bytes_read);
 
5550
  return TRUE;
 
5551
}
 
5552
 
 
5553
static gboolean
 
5554
job_write_in (GIOChannel *channel,
 
5555
              GIOCondition condition,
 
5556
              gpointer user_data)
 
5557
{
 
5558
  Job *job = user_data;
 
5559
  gsize bytes_written;
 
5560
 
 
5561
  if (job->stdin_cursor == NULL || job->stdin_cursor[0] == '\0')
 
5562
    {
 
5563
      /* nothing left to write; remove ourselves */
 
5564
      return FALSE;
 
5565
    }
 
5566
 
 
5567
  g_io_channel_write_chars (channel, job->stdin_cursor, strlen (job->stdin_cursor), &bytes_written, NULL);
 
5568
  g_io_channel_flush (channel, NULL);
 
5569
  job->stdin_cursor += bytes_written;
 
5570
  return TRUE;
 
5571
}
 
5572
 
 
5573
static gboolean
 
5574
job_read_out (GIOChannel *channel,
 
5575
              GIOCondition condition,
 
5576
              gpointer user_data)
 
5577
{
 
5578
  char *s;
 
5579
  char *line;
 
5580
  char buf[1024];
 
5581
  gsize bytes_read;
 
5582
  Job *job = user_data;
 
5583
 
 
5584
  g_io_channel_read_chars (channel, buf, sizeof buf, &bytes_read, NULL);
 
5585
  g_string_append_len (job->stdout_string, buf, bytes_read);
 
5586
 
 
5587
  do
 
5588
    {
 
5589
      gsize line_len;
 
5590
 
 
5591
      s = strstr (job->stdout_string->str + job->stdout_string_cursor, "\n");
 
5592
      if (s == NULL)
 
5593
        break;
 
5594
 
 
5595
      line_len = s - (job->stdout_string->str + job->stdout_string_cursor);
 
5596
      line = g_strndup (job->stdout_string->str + job->stdout_string_cursor, line_len);
 
5597
      job->stdout_string_cursor += line_len + 1;
 
5598
 
 
5599
      //g_print ("helper(pid %5d): '%s'\n", job->pid, line);
 
5600
 
 
5601
      if (strlen (line) < 256)
 
5602
        {
 
5603
          double cur_percentage;
 
5604
          ;
 
5605
 
 
5606
          if (sscanf (line, "udisks-helper-progress: %lg", &cur_percentage) == 1)
 
5607
            {
 
5608
              if (job->device != NULL && job->job_id != NULL)
 
5609
                {
 
5610
                  job->device->priv->job_percentage = cur_percentage;
 
5611
                  emit_job_changed (job->device);
 
5612
                }
 
5613
            }
 
5614
        }
 
5615
 
 
5616
      g_free (line);
 
5617
    }
 
5618
  while (TRUE);
 
5619
 
 
5620
  return TRUE;
 
5621
}
 
5622
 
 
5623
static void
 
5624
job_local_start (Device *device,
 
5625
                 const char *job_id)
 
5626
{
 
5627
  if (device->priv->job != NULL || device->priv->job_in_progress)
 
5628
    {
 
5629
      g_warning ("There is already a job running");
 
5630
      goto out;
 
5631
    }
 
5632
 
 
5633
  g_free (device->priv->job_id);
 
5634
  device->priv->job_id = g_strdup (job_id);
 
5635
  device->priv->job_initiated_by_uid = 0;
 
5636
  device->priv->job_in_progress = TRUE;
 
5637
  device->priv->job_is_cancellable = FALSE;
 
5638
  device->priv->job_percentage = -1.0;
 
5639
 
 
5640
  emit_job_changed (device);
 
5641
 out:
 
5642
  ;
 
5643
}
 
5644
 
 
5645
static void
 
5646
job_local_end (Device *device)
 
5647
{
 
5648
  if (!device->priv->job_in_progress || device->priv->job != NULL)
 
5649
    {
 
5650
      g_warning ("There is no job running");
 
5651
      goto out;
 
5652
    }
 
5653
 
 
5654
  device->priv->job_in_progress = FALSE;
 
5655
  g_free (device->priv->job_id);
 
5656
  device->priv->job_id = NULL;
 
5657
  device->priv->job_initiated_by_uid = 0;
 
5658
  device->priv->job_is_cancellable = FALSE;
 
5659
  device->priv->job_percentage = -1.0;
 
5660
  emit_job_changed (device);
 
5661
 out:
 
5662
  ;
 
5663
}
 
5664
 
 
5665
static gboolean
 
5666
job_new (DBusGMethodInvocation *context,
 
5667
         const char *job_id,
 
5668
         gboolean is_cancellable,
 
5669
         Device *device,
 
5670
         char **argv,
 
5671
         const char *stdin_str,
 
5672
         JobCompletedFunc job_completed_func,
 
5673
         gboolean udev_settle, /* if TRUE, runs udevsettle before returning if the command succeeded */
 
5674
         gpointer user_data,
 
5675
         GDestroyNotify user_data_destroy_func)
 
5676
{
 
5677
  Job *job;
 
5678
  gboolean ret;
 
5679
  GError *error;
 
5680
 
 
5681
  ret = FALSE;
 
5682
  job = NULL;
 
5683
 
 
5684
  PROFILE ("job_new(id=%s, device=%s): start", job_id ? job_id : argv[0], device ? device->priv->device_file : "none");
 
5685
 
 
5686
  if (device != NULL)
 
5687
    {
 
5688
      if (device->priv->job != NULL || device->priv->job_in_progress)
 
5689
        {
 
5690
          throw_error (context, ERROR_BUSY, "There is already a job running");
 
5691
          goto out;
 
5692
        }
 
5693
    }
 
5694
 
 
5695
  job = g_new0 (Job, 1);
 
5696
  job->context = context;
 
5697
  job->device = device != NULL ? DEVICE (g_object_ref (device)) : NULL;
 
5698
  job->job_completed_func = job_completed_func;
 
5699
  job->user_data = user_data;
 
5700
  job->user_data_destroy_func = user_data_destroy_func;
 
5701
  job->stderr_fd = -1;
 
5702
  job->stdout_fd = -1;
 
5703
  job->stdin_fd = -1;
 
5704
  job->stdin_str = g_strdup (stdin_str);
 
5705
  job->stdin_cursor = job->stdin_str;
 
5706
  job->stdout_string = g_string_sized_new (1024);
 
5707
  job->job_id = g_strdup (job_id);
 
5708
  job->udev_settle = udev_settle;
 
5709
 
 
5710
  if (device != NULL && job_id != NULL)
 
5711
    {
 
5712
      g_free (job->device->priv->job_id);
 
5713
      job->device->priv->job_id = g_strdup (job_id);
 
5714
    }
 
5715
 
 
5716
  error = NULL;
 
5717
  if (!g_spawn_async_with_pipes (NULL,
 
5718
                                 argv,
 
5719
                                 NULL,
 
5720
                                 G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
 
5721
                                 NULL,
 
5722
                                 NULL,
 
5723
                                 &(job->pid),
 
5724
                                 stdin_str != NULL ? &(job->stdin_fd) : NULL,
 
5725
                                 &(job->stdout_fd),
 
5726
                                 &(job->stderr_fd),
 
5727
                                 &error))
 
5728
    {
 
5729
      throw_error (context, ERROR_FAILED, "Error starting job: %s", error->message);
 
5730
      g_error_free (error);
 
5731
      goto out;
 
5732
    }
 
5733
 
 
5734
  g_child_watch_add (job->pid, job_child_watch_cb, job);
 
5735
 
 
5736
  job->error_string = g_string_new ("");
 
5737
  job->error_channel = g_io_channel_unix_new (job->stderr_fd);
 
5738
  error = NULL;
 
5739
  if (g_io_channel_set_flags (job->error_channel, G_IO_FLAG_NONBLOCK, &error) != G_IO_STATUS_NORMAL)
 
5740
    {
 
5741
      g_warning ("Cannon set stderr fd for child to be non blocking: %s", error->message);
 
5742
      g_error_free (error);
 
5743
    }
 
5744
  job->error_channel_source_id = g_io_add_watch (job->error_channel, G_IO_IN, job_read_error, job);
 
5745
 
 
5746
  job->out_channel = g_io_channel_unix_new (job->stdout_fd);
 
5747
  error = NULL;
 
5748
  if (g_io_channel_set_flags (job->out_channel, G_IO_FLAG_NONBLOCK, &error) != G_IO_STATUS_NORMAL)
 
5749
    {
 
5750
      g_warning ("Cannon set stdout fd for child to be non blocking: %s", error->message);
 
5751
      g_error_free (error);
 
5752
    }
 
5753
  job->out_channel_source_id = g_io_add_watch (job->out_channel, G_IO_IN, job_read_out, job);
 
5754
 
 
5755
  if (job->stdin_fd >= 0)
 
5756
    {
 
5757
      job->in_channel = g_io_channel_unix_new (job->stdin_fd);
 
5758
      if (g_io_channel_set_flags (job->in_channel, G_IO_FLAG_NONBLOCK, &error) != G_IO_STATUS_NORMAL)
 
5759
        {
 
5760
          g_warning ("Cannon set stdin fd for child to be non blocking: %s", error->message);
 
5761
          g_error_free (error);
 
5762
        }
 
5763
      job->in_channel_source_id = g_io_add_watch (job->in_channel, G_IO_OUT, job_write_in, job);
 
5764
    }
 
5765
 
 
5766
  ret = TRUE;
 
5767
 
 
5768
  if (device != NULL && job_id != NULL)
 
5769
    {
 
5770
      device->priv->job_in_progress = TRUE;
 
5771
      device->priv->job_is_cancellable = is_cancellable;
 
5772
      device->priv->job_percentage = -1.0;
 
5773
      device->priv->job_initiated_by_uid = 0;
 
5774
      if (context != NULL)
 
5775
        {
 
5776
          daemon_local_get_uid (device->priv->daemon, &(device->priv->job_initiated_by_uid), context);
 
5777
        }
 
5778
 
 
5779
      device->priv->job = job;
 
5780
 
 
5781
      emit_job_changed (device);
 
5782
    }
 
5783
 
 
5784
  if (device != NULL)
 
5785
    {
 
5786
      g_print ("helper(pid %5d): launched job %s on %s\n", job->pid, argv[0], device->priv->device_file);
 
5787
    }
 
5788
  else
 
5789
    {
 
5790
      g_print ("helper(pid %5d): launched job %s on daemon\n", job->pid, argv[0]);
 
5791
    }
 
5792
 
 
5793
 out:
 
5794
  if (!ret && job != NULL)
 
5795
    job_free (job);
 
5796
  PROFILE ("job_new(id=%s, device=%s): end", job_id, device ? device->priv->device_file : "none");
 
5797
  return ret;
 
5798
}
 
5799
 
 
5800
/*--------------------------------------------------------------------------------------------------------------*/
 
5801
/* exported methods */
 
5802
 
 
5803
typedef struct
 
5804
{
 
5805
  char *mount_point;
 
5806
  gboolean remove_dir_on_unmount;
 
5807
} MountData;
 
5808
 
 
5809
static MountData *
 
5810
filesystem_mount_data_new (const char *mount_point,
 
5811
                           gboolean remove_dir_on_unmount)
 
5812
{
 
5813
  MountData *data;
 
5814
  data = g_new0 (MountData, 1);
 
5815
  data->mount_point = g_strdup (mount_point);
 
5816
  data->remove_dir_on_unmount = remove_dir_on_unmount;
 
5817
  return data;
 
5818
}
 
5819
 
 
5820
static void
 
5821
filesystem_mount_data_free (MountData *data)
 
5822
{
 
5823
  g_free (data->mount_point);
 
5824
  g_free (data);
 
5825
}
 
5826
 
 
5827
static gboolean
 
5828
is_device_in_fstab (Device *device,
 
5829
                    char **out_mount_point)
 
5830
{
 
5831
  GList *l;
 
5832
  GList *mount_points;
 
5833
  gboolean ret;
 
5834
 
 
5835
  ret = FALSE;
 
5836
 
 
5837
  mount_points = g_unix_mount_points_get (NULL);
 
5838
  for (l = mount_points; l != NULL; l = l->next)
 
5839
    {
 
5840
      GUnixMountPoint *mount_point = l->data;
 
5841
      char canonical_device_file[PATH_MAX];
 
5842
      char *device_path;
 
5843
      char *s;
 
5844
 
 
5845
      device_path = g_strdup (g_unix_mount_point_get_device_path (mount_point));
 
5846
 
 
5847
      /* get the canonical path; e.g. resolve
 
5848
       *
 
5849
       * /dev/disk/by-path/pci-0000:00:1d.7-usb-0:3:1.0-scsi-0:0:0:3-part5
 
5850
       * UUID=78af6939-adac-4ea5-a2a8-576e141da010
 
5851
       * LABEL=foobar
 
5852
       *
 
5853
       * into something like /dev/sde5.
 
5854
       */
 
5855
      if (g_str_has_prefix (device_path, "UUID="))
 
5856
        {
 
5857
          s = device_path;
 
5858
          device_path = g_strdup_printf ("/dev/disk/by-uuid/%s", device_path + 5);
 
5859
          g_free (s);
 
5860
        }
 
5861
      else if (g_str_has_prefix (device_path, "LABEL="))
 
5862
        {
 
5863
          s = device_path;
 
5864
          device_path = g_strdup_printf ("/dev/disk/by-label/%s", device_path + 6);
 
5865
          g_free (s);
 
5866
        }
 
5867
 
 
5868
      if (realpath (device_path, canonical_device_file) == NULL)
 
5869
        {
 
5870
          g_free (device_path);
 
5871
          continue;
 
5872
        }
 
5873
      g_free (device_path);
 
5874
 
 
5875
      if (strcmp (device->priv->device_file, canonical_device_file) == 0)
 
5876
        {
 
5877
          ret = TRUE;
 
5878
          if (out_mount_point != NULL)
 
5879
            *out_mount_point = g_strdup (g_unix_mount_point_get_mount_path (mount_point));
 
5880
          break;
 
5881
        }
 
5882
    }
 
5883
  g_list_foreach (mount_points, (GFunc) g_unix_mount_point_free, NULL);
 
5884
  g_list_free (mount_points);
 
5885
 
 
5886
  return ret;
 
5887
}
 
5888
 
 
5889
typedef struct
 
5890
{
 
5891
  const char *fstype;
 
5892
  const char * const *defaults;
 
5893
  const char * const *allow;
 
5894
  const char * const *allow_uid_self;
 
5895
  const char * const *allow_gid_self;
 
5896
} FSMountOptions;
 
5897
 
 
5898
/* ---------------------- vfat -------------------- */
 
5899
 
 
5900
static const char *vfat_defaults[] = { "uid=", "gid=", "shortname=mixed", "dmask=0077", "utf8=1", "showexec", NULL };
 
5901
static const char *vfat_allow[] = { "flush", "utf8=", "shortname=", "umask=", "dmask=", "fmask=", "codepage=", "iocharset=", "usefree", "showexec", NULL };
 
5902
static const char *vfat_allow_uid_self[] = { "uid=", NULL };
 
5903
static const char *vfat_allow_gid_self[] = { "gid=", NULL };
 
5904
 
 
5905
/* ---------------------- ntfs -------------------- */
 
5906
/* this is assuming that ntfs-3g is used */
 
5907
 
 
5908
static const char *ntfs_defaults[] = { "uid=", "gid=", "dmask=0077", "fmask=0177", NULL };
 
5909
static const char *ntfs_allow[] = { "umask=", "dmask=", "fmask=", NULL };
 
5910
static const char *ntfs_allow_uid_self[] = { "uid=", NULL };
 
5911
static const char *ntfs_allow_gid_self[] = { "gid=", NULL };
 
5912
 
 
5913
/* ---------------------- iso9660 -------------------- */
 
5914
 
 
5915
static const char *iso9660_defaults[] = { "uid=", "gid=", "iocharset=utf8", "mode=0400", "dmode=0500", NULL };
 
5916
static const char *iso9660_allow[] = { "norock", "nojoliet", "iocharset=", "mode=", "dmode=", NULL };
 
5917
static const char *iso9660_allow_uid_self[] = { "uid=", NULL };
 
5918
static const char *iso9660_allow_gid_self[] = { "gid=", NULL };
 
5919
 
 
5920
/* ---------------------- udf -------------------- */
 
5921
 
 
5922
static const char *udf_defaults[] = { "uid=", "gid=", "iocharset=utf8", "umask=0077", NULL };
 
5923
static const char *udf_allow[] = { "iocharset=", "umask=", "mode=", "dmode=", NULL };
 
5924
static const char *udf_allow_uid_self[] = { "uid=", NULL };
 
5925
static const char *udf_allow_gid_self[] = { "gid=", NULL };
 
5926
 
 
5927
/* ------------------------------------------------ */
 
5928
/* TODO: support context= */
 
5929
 
 
5930
static const char *any_allow[] = { "exec", "noexec", "nodev", "nosuid", "atime", "noatime", "nodiratime", "ro", "rw", "sync", "dirsync", NULL };
 
5931
 
 
5932
static const FSMountOptions fs_mount_options[] =
 
5933
  {
 
5934
    { "vfat", vfat_defaults, vfat_allow, vfat_allow_uid_self, vfat_allow_gid_self },
 
5935
    { "ntfs", ntfs_defaults, ntfs_allow, ntfs_allow_uid_self, ntfs_allow_gid_self },
 
5936
    { "iso9660", iso9660_defaults, iso9660_allow, iso9660_allow_uid_self, iso9660_allow_gid_self },
 
5937
    { "udf", udf_defaults, udf_allow, udf_allow_uid_self, udf_allow_gid_self },
 
5938
  };
 
5939
 
 
5940
static const gchar *well_known_filesystems[] =
 
5941
{
 
5942
  "btrfs",
 
5943
  "ext2",
 
5944
  "ext3",
 
5945
  "ext4",
 
5946
  "udf",
 
5947
  "iso9660",
 
5948
  "xfs",
 
5949
  "jfs",
 
5950
  "nilfs",
 
5951
  "reiserfs",
 
5952
  "reiser4",
 
5953
  "msdos",
 
5954
  "umsdos",
 
5955
  "vfat",
 
5956
  "exfat",
 
5957
  "ntfs",
 
5958
  NULL,
 
5959
};
 
5960
 
 
5961
/* ------------------------------------------------ */
 
5962
 
 
5963
static int num_fs_mount_options = sizeof(fs_mount_options) / sizeof(FSMountOptions);
 
5964
 
 
5965
static const FSMountOptions *
 
5966
find_mount_options_for_fs (const char *fstype)
 
5967
{
 
5968
  int n;
 
5969
  const FSMountOptions *fsmo;
 
5970
 
 
5971
  for (n = 0; n < num_fs_mount_options; n++)
 
5972
    {
 
5973
      fsmo = fs_mount_options + n;
 
5974
      if (strcmp (fsmo->fstype, fstype) == 0)
 
5975
        goto out;
 
5976
    }
 
5977
 
 
5978
  fsmo = NULL;
 
5979
 out:
 
5980
  return fsmo;
 
5981
}
 
5982
 
 
5983
static gid_t
 
5984
find_primary_gid (uid_t uid)
 
5985
{
 
5986
  struct passwd *pw;
 
5987
  gid_t gid;
 
5988
 
 
5989
  gid = (gid_t) - 1;
 
5990
 
 
5991
  pw = getpwuid (uid);
 
5992
  if (pw == NULL)
 
5993
    {
 
5994
      g_warning ("Couldn't look up uid %d: %m", uid);
 
5995
      goto out;
 
5996
    }
 
5997
  gid = pw->pw_gid;
 
5998
 
 
5999
 out:
 
6000
  return gid;
 
6001
}
 
6002
 
 
6003
static gboolean
 
6004
is_uid_in_gid (uid_t uid,
 
6005
               gid_t gid)
 
6006
{
 
6007
  gboolean ret;
 
6008
  struct passwd *pw;
 
6009
  static gid_t supplementary_groups[128];
 
6010
  int num_supplementary_groups = 128;
 
6011
  int n;
 
6012
 
 
6013
  /* TODO: use some #define instead of harcoding some random number like 128 */
 
6014
 
 
6015
  ret = FALSE;
 
6016
 
 
6017
  pw = getpwuid (uid);
 
6018
  if (pw == NULL)
 
6019
    {
 
6020
      g_warning ("Couldn't look up uid %d: %m", uid);
 
6021
      goto out;
 
6022
    }
 
6023
  if (pw->pw_gid == gid)
 
6024
    {
 
6025
      ret = TRUE;
 
6026
      goto out;
 
6027
    }
 
6028
 
 
6029
  if (getgrouplist (pw->pw_name, pw->pw_gid, supplementary_groups, &num_supplementary_groups) < 0)
 
6030
    {
 
6031
      g_warning ("Couldn't find supplementary groups for uid %d: %m", uid);
 
6032
      goto out;
 
6033
    }
 
6034
 
 
6035
  for (n = 0; n < num_supplementary_groups; n++)
 
6036
    {
 
6037
      if (supplementary_groups[n] == gid)
 
6038
        {
 
6039
          ret = TRUE;
 
6040
          goto out;
 
6041
        }
 
6042
    }
 
6043
 
 
6044
 out:
 
6045
  return ret;
 
6046
}
 
6047
 
 
6048
static gboolean
 
6049
is_mount_option_allowed (const FSMountOptions *fsmo,
 
6050
                         const char *option,
 
6051
                         uid_t caller_uid)
 
6052
{
 
6053
  int n;
 
6054
  char *endp;
 
6055
  uid_t uid;
 
6056
  gid_t gid;
 
6057
  gboolean allowed;
 
6058
  const char *ep;
 
6059
  gsize ep_len;
 
6060
 
 
6061
  allowed = FALSE;
 
6062
 
 
6063
  /* first run through the allowed mount options */
 
6064
  if (fsmo != NULL)
 
6065
    {
 
6066
      for (n = 0; fsmo->allow != NULL && fsmo->allow[n] != NULL; n++)
 
6067
        {
 
6068
          ep = strstr (fsmo->allow[n], "=");
 
6069
          if (ep != NULL && ep[1] == '\0')
 
6070
            {
 
6071
              ep_len = ep - fsmo->allow[n] + 1;
 
6072
              if (strncmp (fsmo->allow[n], option, ep_len) == 0)
 
6073
                {
 
6074
                  allowed = TRUE;
 
6075
                  goto out;
 
6076
                }
 
6077
            }
 
6078
          else
 
6079
            {
 
6080
              if (strcmp (fsmo->allow[n], option) == 0)
 
6081
                {
 
6082
                  allowed = TRUE;
 
6083
                  goto out;
 
6084
                }
 
6085
            }
 
6086
        }
 
6087
    }
 
6088
  for (n = 0; any_allow[n] != NULL; n++)
 
6089
    {
 
6090
      ep = strstr (any_allow[n], "=");
 
6091
      if (ep != NULL && ep[1] == '\0')
 
6092
        {
 
6093
          ep_len = ep - any_allow[n] + 1;
 
6094
          if (strncmp (any_allow[n], option, ep_len) == 0)
 
6095
            {
 
6096
              allowed = TRUE;
 
6097
              goto out;
 
6098
            }
 
6099
        }
 
6100
      else
 
6101
        {
 
6102
          if (strcmp (any_allow[n], option) == 0)
 
6103
            {
 
6104
              allowed = TRUE;
 
6105
              goto out;
 
6106
            }
 
6107
        }
 
6108
    }
 
6109
 
 
6110
  /* .. then check for mount options where the caller is allowed to pass
 
6111
   * in his own uid
 
6112
   */
 
6113
  if (fsmo != NULL)
 
6114
    {
 
6115
      for (n = 0; fsmo->allow_uid_self != NULL && fsmo->allow_uid_self[n] != NULL; n++)
 
6116
        {
 
6117
          const char *r_mount_option = fsmo->allow_uid_self[n];
 
6118
          if (g_str_has_prefix (option, r_mount_option))
 
6119
            {
 
6120
              uid = strtol (option + strlen (r_mount_option), &endp, 10);
 
6121
              if (*endp != '\0')
 
6122
                continue;
 
6123
              if (uid == caller_uid)
 
6124
                {
 
6125
                  allowed = TRUE;
 
6126
                  goto out;
 
6127
                }
 
6128
            }
 
6129
        }
 
6130
    }
 
6131
 
 
6132
  /* .. ditto for gid
 
6133
   */
 
6134
  if (fsmo != NULL)
 
6135
    {
 
6136
      for (n = 0; fsmo->allow_gid_self != NULL && fsmo->allow_gid_self[n] != NULL; n++)
 
6137
        {
 
6138
          const char *r_mount_option = fsmo->allow_gid_self[n];
 
6139
          if (g_str_has_prefix (option, r_mount_option))
 
6140
            {
 
6141
              gid = strtol (option + strlen (r_mount_option), &endp, 10);
 
6142
              if (*endp != '\0')
 
6143
                continue;
 
6144
              if (is_uid_in_gid (caller_uid, gid))
 
6145
                {
 
6146
                  allowed = TRUE;
 
6147
                  goto out;
 
6148
                }
 
6149
            }
 
6150
        }
 
6151
    }
 
6152
 
 
6153
 out:
 
6154
  return allowed;
 
6155
}
 
6156
 
 
6157
static char **
 
6158
prepend_default_mount_options (Device *device,
 
6159
                               const FSMountOptions *fsmo,
 
6160
                               uid_t caller_uid,
 
6161
                               char **given_options)
 
6162
{
 
6163
  GPtrArray *options;
 
6164
  int n;
 
6165
  char *s;
 
6166
  gid_t gid;
 
6167
 
 
6168
  /* static default options from FSMountOptions */
 
6169
  options = g_ptr_array_new ();
 
6170
  if (fsmo != NULL)
 
6171
    {
 
6172
      for (n = 0; fsmo->defaults != NULL && fsmo->defaults[n] != NULL; n++)
 
6173
        {
 
6174
          const char *option = fsmo->defaults[n];
 
6175
 
 
6176
          if (strcmp (option, "uid=") == 0)
 
6177
            {
 
6178
              s = g_strdup_printf ("uid=%d", caller_uid);
 
6179
              g_ptr_array_add (options, s);
 
6180
            }
 
6181
          else if (strcmp (option, "gid=") == 0)
 
6182
            {
 
6183
              gid = find_primary_gid (caller_uid);
 
6184
              if (gid != (gid_t) - 1)
 
6185
                {
 
6186
                  s = g_strdup_printf ("gid=%d", gid);
 
6187
                  g_ptr_array_add (options, s);
 
6188
                }
 
6189
            }
 
6190
          else
 
6191
            {
 
6192
              g_ptr_array_add (options, g_strdup (option));
 
6193
            }
 
6194
        }
 
6195
    }
 
6196
 
 
6197
  /* dynamic default options */
 
6198
 
 
6199
  /* some broken DVDs come with 0400 directory permissions, making them
 
6200
   * unreadable; overwrite readonly UDF media with a 0500 dmode. */
 
6201
  if (g_strcmp0 (device->priv->id_type, "udf") == 0 && device->priv->device_is_optical_disc &&
 
6202
      device->priv->drive_media != NULL && 
 
6203
      strstr(device->priv->drive_media, "_rw") == NULL && strstr(device->priv->drive_media, "_ram") == NULL)
 
6204
    {
 
6205
      g_ptr_array_add (options, g_strdup("dmode=0500"));
 
6206
    }
 
6207
 
 
6208
  /* user supplied options */
 
6209
  for (n = 0; given_options[n] != NULL; n++)
 
6210
    {
 
6211
      g_ptr_array_add (options, g_strdup (given_options[n]));
 
6212
    }
 
6213
 
 
6214
  g_ptr_array_add (options, NULL);
 
6215
 
 
6216
  return (char **) g_ptr_array_free (options, FALSE);
 
6217
}
 
6218
 
 
6219
static void
 
6220
unlock_cd_tray (Device *device)
 
6221
{
 
6222
  /* Unlock CD tray to keep the hardware eject button working */
 
6223
  if (g_udev_device_has_property (device->priv->d, "ID_CDROM"))
 
6224
    {
 
6225
      gint fd;
 
6226
 
 
6227
      g_print ("**** Unlocking CD-ROM door for %s\n", device->priv->device_file);
 
6228
      fd = open (device->priv->device_file, O_RDONLY);
 
6229
      if (fd > 0)
 
6230
        {
 
6231
          if (ioctl (fd, CDROM_LOCKDOOR, 0) != 0)
 
6232
            g_warning ("Could not unlock CD-ROM door: %s", strerror (errno));
 
6233
          close (fd);
 
6234
        }
 
6235
      else
 
6236
        {
 
6237
          g_warning ("Could not open CD-ROM device: %s", strerror (errno));
 
6238
        }
 
6239
    }
 
6240
}
 
6241
 
 
6242
static void
 
6243
filesystem_mount_completed_cb (DBusGMethodInvocation *context,
 
6244
                               Device *device,
 
6245
                               gboolean job_was_cancelled,
 
6246
                               int status,
 
6247
                               const char *stderr,
 
6248
                               const char *stdout,
 
6249
                               gpointer user_data)
 
6250
{
 
6251
  MountData *data = (MountData *) user_data;
 
6252
  uid_t uid;
 
6253
 
 
6254
  daemon_local_get_uid (device->priv->daemon, &uid, context);
 
6255
 
 
6256
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
6257
    {
 
6258
 
 
6259
      update_info (device);
 
6260
      drain_pending_changes (device, FALSE);
 
6261
      /* If the kernel and device support sending EJECT_REQUEST change uevents
 
6262
       * and we use in-kernel polling, keep the door locked, as udev calls
 
6263
       * eject on pressing the button.  Otherwise unlock it, to keep the
 
6264
       * hardware button working without userspace support */
 
6265
      if (!device->priv->using_in_kernel_polling)
 
6266
        unlock_cd_tray (device);
 
6267
 
 
6268
      dbus_g_method_return (context, data->mount_point);
 
6269
    }
 
6270
  else
 
6271
    {
 
6272
      if (data->remove_dir_on_unmount)
 
6273
        {
 
6274
          mount_file_remove (device->priv->device_file, data->mount_point);
 
6275
          if (g_rmdir (data->mount_point) != 0)
 
6276
            {
 
6277
              g_warning ("Error removing dir in late mount error path: %m");
 
6278
            }
 
6279
        }
 
6280
 
 
6281
      if (job_was_cancelled)
 
6282
        {
 
6283
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
6284
        }
 
6285
      else if (WEXITSTATUS (status) == 32)
 
6286
        {
 
6287
          throw_error (context, ERROR_FILESYSTEM_DRIVER_MISSING, "Error mounting: %s", stderr);
 
6288
        }
 
6289
      else
 
6290
        {
 
6291
          throw_error (context,
 
6292
                       ERROR_FAILED,
 
6293
                       "Error mounting: mount exited with exit code %d: %s",
 
6294
                       WEXITSTATUS (status),
 
6295
                       stderr);
 
6296
        }
 
6297
    }
 
6298
}
 
6299
 
 
6300
static gboolean
 
6301
is_in_filesystem_file (const gchar *filesystems_file,
 
6302
                       const gchar *fstype)
 
6303
{
 
6304
  gchar *filesystems;
 
6305
  GError *error;
 
6306
  gboolean ret;
 
6307
  gchar **lines;
 
6308
  guint n;
 
6309
 
 
6310
  ret = FALSE;
 
6311
  filesystems = NULL;
 
6312
  lines = NULL;
 
6313
 
 
6314
  error = NULL;
 
6315
  if (!g_file_get_contents (filesystems_file,
 
6316
                            &filesystems,
 
6317
                            NULL, /* gsize *out_length */
 
6318
                            &error))
 
6319
    {
 
6320
      g_warning ("Error reading %s: %s (%s %d)",
 
6321
                 filesystems_file,
 
6322
                 error->message,
 
6323
                 g_quark_to_string (error->domain),
 
6324
                 error->code);
 
6325
      g_error_free (error);
 
6326
      goto out;
 
6327
    }
 
6328
 
 
6329
  lines = g_strsplit (filesystems, "\n", -1);
 
6330
  for (n = 0; lines != NULL && lines[n] != NULL && !ret; n++)
 
6331
    {
 
6332
      gchar **tokens;
 
6333
      gint num_tokens;
 
6334
      g_strdelimit (lines[n], " \t", ' ');
 
6335
      g_strstrip (lines[n]);
 
6336
      tokens = g_strsplit (lines[n], " ", -1);
 
6337
      num_tokens = g_strv_length (tokens);
 
6338
      if (num_tokens == 1 && g_strcmp0 (tokens[0], fstype) == 0)
 
6339
        {
 
6340
          ret = TRUE;
 
6341
        }
 
6342
      g_strfreev (tokens);
 
6343
    }
 
6344
 
 
6345
 out:
 
6346
  g_strfreev (lines);
 
6347
  g_free (filesystems);
 
6348
  return ret;
 
6349
}
 
6350
 
 
6351
static gboolean
 
6352
is_well_known_filesystem (const gchar *fstype)
 
6353
{
 
6354
  gboolean ret;
 
6355
  guint n;
 
6356
 
 
6357
  ret = FALSE;
 
6358
  for (n = 0; well_known_filesystems[n] != NULL; n++)
 
6359
    {
 
6360
      if (g_strcmp0 (well_known_filesystems[n], fstype) == 0)
 
6361
        {
 
6362
          ret = TRUE;
 
6363
          goto out;
 
6364
        }
 
6365
    }
 
6366
 out:
 
6367
  return ret;
 
6368
}
 
6369
 
 
6370
/* this is not a very efficient implementation but it's very rarely
 
6371
 * called so no real point in optimizing it...
 
6372
 */
 
6373
static gboolean
 
6374
is_allowed_filesystem (const gchar *fstype)
 
6375
{
 
6376
  return is_well_known_filesystem (fstype) ||
 
6377
    is_in_filesystem_file ("/proc/filesystems", fstype) ||
 
6378
    is_in_filesystem_file ("/etc/filesystems", fstype);
 
6379
}
 
6380
 
 
6381
static void
 
6382
device_filesystem_mount_authorized_cb (Daemon *daemon,
 
6383
                                       Device *device,
 
6384
                                       DBusGMethodInvocation *context,
 
6385
                                       const gchar *action_id,
 
6386
                                       guint num_user_data,
 
6387
                                       gpointer *user_data_elements)
 
6388
{
 
6389
  const gchar *filesystem_type = user_data_elements[0];
 
6390
  gchar **given_options = user_data_elements[1];
 
6391
  int n;
 
6392
  GString *s;
 
6393
  char *argv[10];
 
6394
  char *mount_point;
 
6395
  char *fstype;
 
6396
  char *mount_options;
 
6397
  GError *error;
 
6398
  uid_t caller_uid;
 
6399
  gboolean remove_dir_on_unmount;
 
6400
  const FSMountOptions *fsmo;
 
6401
  char **options;
 
6402
  char uid_buf[32];
 
6403
 
 
6404
  fstype = NULL;
 
6405
  options = NULL;
 
6406
  mount_options = NULL;
 
6407
  mount_point = NULL;
 
6408
  remove_dir_on_unmount = FALSE;
 
6409
  error = NULL;
 
6410
 
 
6411
  /* If the user requests the filesystem type, error out unless the
 
6412
   * filesystem type is
 
6413
   *
 
6414
   * - well-known [1]; or
 
6415
   * - in the /proc/filesystems file; or
 
6416
   * - in the /etc/filesystems file
 
6417
   *
 
6418
   * in that order. We do this because mount(8) on Linux allows
 
6419
   * loading any arbitrary kernel module (when invoked as root) by
 
6420
   * passing something appropriate to the -t option. So we have to
 
6421
   * validate whatever we pass...
 
6422
   *
 
6423
   * See https://bugs.freedesktop.org/show_bug.cgi?id=32232 for more
 
6424
   * details.
 
6425
   *
 
6426
   * [1] : since /etc/filesystems may be horribly out of date and not
 
6427
   *       contain e.g. ext4
 
6428
   */
 
6429
  if (filesystem_type != NULL && strlen (filesystem_type) > 0 &&
 
6430
      g_strcmp0 (filesystem_type, "auto") != 0)
 
6431
    {
 
6432
      if (!is_allowed_filesystem (filesystem_type))
 
6433
        {
 
6434
          throw_error (context, ERROR_FAILED,
 
6435
                       "Requested filesystem type is neither well-known nor "
 
6436
                       "in /proc/filesystems nor in /etc/filesystems");
 
6437
          goto out;
 
6438
        }
 
6439
    }
 
6440
 
 
6441
  daemon_local_get_uid (device->priv->daemon, &caller_uid, context);
 
6442
 
 
6443
  if (device->priv->id_usage == NULL || strcmp (device->priv->id_usage, "filesystem") != 0)
 
6444
    {
 
6445
      if ((g_strcmp0 (filesystem_type, "auto") == 0 || g_strcmp0 (filesystem_type, "") == 0) && device->priv->id_usage
 
6446
          == NULL)
 
6447
        {
 
6448
          /* if we don't know the usage of the device and 'auto' or '' is passed for fstype
 
6449
           * then just try that.. this is to make, for example, mounting /dev/fd0 work (we
 
6450
           * don't probe such devices for filesystems in udev)
 
6451
           */
 
6452
        }
 
6453
      else
 
6454
        {
 
6455
          throw_error (context, ERROR_FAILED, "Not a mountable file system");
 
6456
          goto out;
 
6457
        }
 
6458
    }
 
6459
 
 
6460
  if (device_local_is_busy (device, FALSE, TRUE, &error))
 
6461
    {
 
6462
      dbus_g_method_return_error (context, error);
 
6463
      g_error_free (error);
 
6464
      goto out;
 
6465
    }
 
6466
 
 
6467
  /* Check if the device is referenced in /etc/fstab; if so, attempt to
 
6468
   * mount the device as the user
 
6469
   */
 
6470
  if (is_device_in_fstab (device, &mount_point))
 
6471
    {
 
6472
      n = 0;
 
6473
      snprintf (uid_buf, sizeof uid_buf, "%d", caller_uid);
 
6474
      argv[n++] = "udisks-helper-fstab-mounter";
 
6475
      argv[n++] = "mount";
 
6476
      argv[n++] = device->priv->device_file;
 
6477
      argv[n++] = uid_buf;
 
6478
      argv[n++] = NULL;
 
6479
      goto run_job;
 
6480
    }
 
6481
 
 
6482
  /* set the fstype */
 
6483
  fstype = NULL;
 
6484
  if (strlen (filesystem_type) == 0)
 
6485
    {
 
6486
      if (device->priv->id_type != NULL && strlen (device->priv->id_type) > 0)
 
6487
        {
 
6488
          fstype = g_strdup (device->priv->id_type);
 
6489
        }
 
6490
      else
 
6491
        {
 
6492
          fstype = g_strdup ("auto");
 
6493
        }
 
6494
    }
 
6495
  else
 
6496
    {
 
6497
      fstype = g_strdup (filesystem_type);
 
6498
    }
 
6499
 
 
6500
  fsmo = find_mount_options_for_fs (fstype);
 
6501
 
 
6502
  /* always prepend some reasonable default mount options; these are
 
6503
   * chosen here; the user can override them if he wants to
 
6504
   */
 
6505
  options = prepend_default_mount_options (device, fsmo, caller_uid, given_options);
 
6506
 
 
6507
  /* validate mount options and check for authorizations */
 
6508
  s = g_string_new ("uhelper=udisks,nodev,nosuid");
 
6509
  for (n = 0; options[n] != NULL; n++)
 
6510
    {
 
6511
      const char *option = options[n];
 
6512
 
 
6513
      /* avoid attacks like passing "shortname=lower,uid=0" as a single mount option */
 
6514
      if (strstr (option, ",") != NULL)
 
6515
        {
 
6516
          throw_error (context, ERROR_INVALID_OPTION, "Malformed mount option: ", option);
 
6517
          g_string_free (s, TRUE);
 
6518
          goto out;
 
6519
        }
 
6520
 
 
6521
      /* first check if the mount option is allowed */
 
6522
      if (!is_mount_option_allowed (fsmo, option, caller_uid))
 
6523
        {
 
6524
          throw_error (context, ERROR_INVALID_OPTION, "Mount option %s is not allowed", option);
 
6525
          g_string_free (s, TRUE);
 
6526
          goto out;
 
6527
        }
 
6528
 
 
6529
      g_string_append_c (s, ',');
 
6530
      g_string_append (s, option);
 
6531
    }
 
6532
  mount_options = g_string_free (s, FALSE);
 
6533
 
 
6534
  g_print ("**** USING MOUNT OPTIONS '%s' FOR DEVICE %s\n", mount_options, device->priv->device_file);
 
6535
 
 
6536
  if (device->priv->device_is_mounted)
 
6537
    {
 
6538
      throw_error (context, ERROR_FAILED, "Device is already mounted");
 
6539
      goto out;
 
6540
    }
 
6541
 
 
6542
  /* Determine the mount point to use.
 
6543
   *
 
6544
   * TODO: use characteristics of the drive such as the name, connection etc.
 
6545
   *       to get better names (/media/disk is kinda lame).
 
6546
   */
 
6547
  if (device->priv->id_label != NULL && strlen (device->priv->id_label) > 0)
 
6548
    {
 
6549
      GString * s;
 
6550
 
 
6551
      s = g_string_new ("/media/");
 
6552
      for (n = 0; device->priv->id_label[n] != '\0'; n++)
 
6553
        {
 
6554
          gint c = device->priv->id_label[n];
 
6555
          if (c == '/')
 
6556
            g_string_append_c (s, '_');
 
6557
          else
 
6558
            g_string_append_c (s, c);
 
6559
        }
 
6560
 
 
6561
      mount_point = g_string_free (s, FALSE);
 
6562
    }
 
6563
  else if (device->priv->id_uuid != NULL && strlen (device->priv->id_uuid) > 0)
 
6564
    {
 
6565
 
 
6566
      GString * s;
 
6567
 
 
6568
      s = g_string_new ("/media/");
 
6569
      for (n = 0; device->priv->id_uuid[n] != '\0'; n++)
 
6570
        {
 
6571
          gint c = device->priv->id_uuid[n];
 
6572
          if (c == '/')
 
6573
            g_string_append_c (s, '_');
 
6574
          else
 
6575
            g_string_append_c (s, c);
 
6576
        }
 
6577
 
 
6578
      mount_point = g_string_free (s, FALSE);
 
6579
 
 
6580
    }
 
6581
  else
 
6582
    {
 
6583
      mount_point = g_strdup ("/media/disk");
 
6584
    }
 
6585
 
 
6586
 try_another_mount_point:
 
6587
  /* ... then uniqify the mount point and mkdir it */
 
6588
  if (g_file_test (mount_point, G_FILE_TEST_EXISTS))
 
6589
    {
 
6590
      char *s = mount_point;
 
6591
      /* TODO: append numbers instead of _, __ and so on */
 
6592
      mount_point = g_strdup_printf ("%s_", mount_point);
 
6593
      g_free (s);
 
6594
      goto try_another_mount_point;
 
6595
    }
 
6596
 
 
6597
  remove_dir_on_unmount = TRUE;
 
6598
 
 
6599
  if (g_mkdir (mount_point, 0700) != 0)
 
6600
    {
 
6601
      throw_error (context, ERROR_FAILED, "Error creating moint point: %m");
 
6602
      goto out;
 
6603
    }
 
6604
 
 
6605
  /* now that we have a mount point, immediately add it to the
 
6606
   * /var/lib/udisks/mtab file.
 
6607
   *
 
6608
   * If mounting fails we'll clean it up in filesystem_mount_completed_cb. If it
 
6609
   * hangs we'll clean it up the next time we start up.
 
6610
   */
 
6611
  mount_file_add (device->priv->device_file, mount_point, caller_uid, remove_dir_on_unmount);
 
6612
 
 
6613
  n = 0;
 
6614
  argv[n++] = "mount";
 
6615
  argv[n++] = "-t";
 
6616
  argv[n++] = fstype;
 
6617
  argv[n++] = "-o";
 
6618
  argv[n++] = mount_options;
 
6619
  argv[n++] = device->priv->device_file;
 
6620
  argv[n++] = mount_point;
 
6621
  argv[n++] = NULL;
 
6622
 
 
6623
 run_job:
 
6624
 
 
6625
  error = NULL;
 
6626
  if (!job_new (context,
 
6627
                "FilesystemMount",
 
6628
                FALSE,
 
6629
                device,
 
6630
                argv,
 
6631
                NULL,
 
6632
                filesystem_mount_completed_cb,
 
6633
                FALSE,
 
6634
                filesystem_mount_data_new (mount_point, remove_dir_on_unmount),
 
6635
                (GDestroyNotify) filesystem_mount_data_free))
 
6636
    {
 
6637
      if (remove_dir_on_unmount)
 
6638
        {
 
6639
          mount_file_remove (device->priv->device_file, mount_point);
 
6640
          if (g_rmdir (mount_point) != 0)
 
6641
            {
 
6642
              g_warning ("Error removing dir in early mount error path: %m");
 
6643
            }
 
6644
        }
 
6645
      goto out;
 
6646
    }
 
6647
 
 
6648
 out:
 
6649
  g_free (fstype);
 
6650
  g_free (mount_options);
 
6651
  g_free (mount_point);
 
6652
  g_strfreev (options);
 
6653
}
 
6654
 
 
6655
gboolean
 
6656
device_filesystem_mount (Device *device,
 
6657
                         const char *filesystem_type,
 
6658
                         char **given_options,
 
6659
                         DBusGMethodInvocation *context)
 
6660
{
 
6661
  const gchar *action_id;
 
6662
  gboolean auth_no_user_interaction;
 
6663
  gchar **options_to_pass;
 
6664
  guint n;
 
6665
  guint m;
 
6666
 
 
6667
  if (is_device_in_fstab (device, NULL))
 
6668
    {
 
6669
      action_id = NULL;
 
6670
    }
 
6671
  else
 
6672
    {
 
6673
      if (device->priv->device_is_system_internal)
 
6674
        action_id = "org.freedesktop.udisks.filesystem-mount-system-internal";
 
6675
      else
 
6676
        action_id = "org.freedesktop.udisks.filesystem-mount";
 
6677
    }
 
6678
 
 
6679
  auth_no_user_interaction = FALSE;
 
6680
  options_to_pass = g_strdupv (given_options);
 
6681
  for (n = 0; options_to_pass != NULL && options_to_pass[n] != NULL; n++)
 
6682
    {
 
6683
      if (g_strcmp0 (options_to_pass[n], "auth_no_user_interaction") == 0)
 
6684
        {
 
6685
          auth_no_user_interaction = TRUE;
 
6686
          g_free (options_to_pass[n]);
 
6687
          for (m = n; options_to_pass[m + 1] != NULL; m++)
 
6688
            options_to_pass[m] = options_to_pass[m + 1];
 
6689
          options_to_pass[m] = NULL;
 
6690
          break;
 
6691
        }
 
6692
    }
 
6693
 
 
6694
  daemon_local_check_auth (device->priv->daemon,
 
6695
                           device,
 
6696
                           action_id,
 
6697
                           "FilesystemMount",
 
6698
                           !auth_no_user_interaction,
 
6699
                           device_filesystem_mount_authorized_cb,
 
6700
                           context,
 
6701
                           2,
 
6702
                           g_strdup (filesystem_type),
 
6703
                           g_free,
 
6704
                           options_to_pass,
 
6705
                           g_strfreev);
 
6706
 
 
6707
  return TRUE;
 
6708
}
 
6709
 
 
6710
/*--------------------------------------------------------------------------------------------------------------*/
 
6711
 
 
6712
static void
 
6713
filesystem_unmount_completed_cb (DBusGMethodInvocation *context,
 
6714
                                 Device *device,
 
6715
                                 gboolean job_was_cancelled,
 
6716
                                 int status,
 
6717
                                 const char *stderr,
 
6718
                                 const char *stdout,
 
6719
                                 gpointer user_data)
 
6720
{
 
6721
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
6722
    {
 
6723
      /* update_info_mount_state() will update the mounts file and clean up the directory if needed */
 
6724
      update_info (device);
 
6725
      if (context != NULL)
 
6726
          dbus_g_method_return (context);
 
6727
    }
 
6728
  else
 
6729
    {
 
6730
      if (job_was_cancelled)
 
6731
        {
 
6732
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
6733
        }
 
6734
      else
 
6735
        {
 
6736
          if (strstr (stderr, "device is busy") != NULL)
 
6737
            {
 
6738
              throw_error (context, ERROR_BUSY, "Cannot unmount because file system on device is busy");
 
6739
            }
 
6740
          else
 
6741
            {
 
6742
              throw_error (context,
 
6743
                           ERROR_FAILED,
 
6744
                           "Error unmounting: umount exited with exit code %d: %s",
 
6745
                           WEXITSTATUS (status),
 
6746
                           stderr);
 
6747
            }
 
6748
        }
 
6749
    }
 
6750
}
 
6751
 
 
6752
static void
 
6753
device_filesystem_unmount_authorized_cb (Daemon *daemon,
 
6754
                                         Device *device,
 
6755
                                         DBusGMethodInvocation *context,
 
6756
                                         const gchar *action_id,
 
6757
                                         guint num_user_data,
 
6758
                                         gpointer *user_data_elements)
 
6759
{
 
6760
  gchar **options = user_data_elements[0];
 
6761
  int n;
 
6762
  char *argv[16];
 
6763
  gboolean force_unmount;
 
6764
  char *mount_path;
 
6765
  uid_t uid;
 
6766
  gchar uid_buf[32];
 
6767
 
 
6768
  mount_path = NULL;
 
6769
 
 
6770
  if (!device->priv->device_is_mounted || device->priv->device_mount_paths->len == 0)
 
6771
    {
 
6772
      throw_error (context, ERROR_FAILED, "Device is not mounted");
 
6773
      goto out;
 
6774
    }
 
6775
 
 
6776
  force_unmount = FALSE;
 
6777
  for (n = 0; options[n] != NULL; n++)
 
6778
    {
 
6779
      char *option = options[n];
 
6780
      if (strcmp ("force", option) == 0)
 
6781
        {
 
6782
          force_unmount = TRUE;
 
6783
        }
 
6784
      else
 
6785
        {
 
6786
          throw_error (context, ERROR_INVALID_OPTION, "Unknown option %s", option);
 
6787
          goto out;
 
6788
        }
 
6789
    }
 
6790
 
 
6791
  daemon_local_get_uid (device->priv->daemon, &uid, context);
 
6792
  g_snprintf (uid_buf, sizeof uid_buf, "%d", uid);
 
6793
 
 
6794
  if (!mount_file_has_device (device->priv->device_file, NULL, NULL))
 
6795
    {
 
6796
      if (is_device_in_fstab (device, &mount_path))
 
6797
        {
 
6798
 
 
6799
          n = 0;
 
6800
          argv[n++] = "udisks-helper-fstab-mounter";
 
6801
          if (force_unmount)
 
6802
            argv[n++] = "force_unmount";
 
6803
          else
 
6804
            argv[n++] = "unmount";
 
6805
          argv[n++] = device->priv->device_file;
 
6806
          argv[n++] = uid_buf;
 
6807
          argv[n++] = NULL;
 
6808
          goto run_job;
 
6809
        }
 
6810
 
 
6811
      /* otherwise the user will have the .unmount-others authorization per the logic in
 
6812
       * device_filesystem_unmount()
 
6813
       */
 
6814
    }
 
6815
 
 
6816
  mount_path = g_strdup (((gchar **) device->priv->device_mount_paths->pdata)[0]);
 
6817
 
 
6818
  n = 0;
 
6819
  argv[n++] = "umount";
 
6820
  if (force_unmount)
 
6821
    {
 
6822
      /* on Linux we currently only have lazy unmount to emulate this */
 
6823
      argv[n++] = "-l";
 
6824
    }
 
6825
  argv[n++] = mount_path;
 
6826
  argv[n++] = NULL;
 
6827
 
 
6828
 run_job:
 
6829
  if (!job_new (context,
 
6830
                "FilesystemUnmount",
 
6831
                FALSE,
 
6832
                device,
 
6833
                argv,
 
6834
                NULL,
 
6835
                filesystem_unmount_completed_cb,
 
6836
                FALSE,
 
6837
                g_strdup (mount_path),
 
6838
                g_free))
 
6839
    {
 
6840
      goto out;
 
6841
    }
 
6842
 
 
6843
 out:
 
6844
  g_free (mount_path);
 
6845
}
 
6846
 
 
6847
gboolean
 
6848
device_filesystem_unmount (Device *device,
 
6849
                           char **options,
 
6850
                           DBusGMethodInvocation *context)
 
6851
{
 
6852
  const gchar *action_id;
 
6853
  uid_t uid_of_mount;
 
6854
 
 
6855
  if (!device->priv->device_is_mounted || device->priv->device_mount_paths->len == 0)
 
6856
    {
 
6857
      throw_error (context, ERROR_FAILED, "Device is not mounted");
 
6858
      goto out;
 
6859
    }
 
6860
 
 
6861
  /* if device is in /etc/fstab, then we'll run unmount as the calling user */
 
6862
  action_id = NULL;
 
6863
  if (!mount_file_has_device (device->priv->device_file, &uid_of_mount, NULL))
 
6864
    {
 
6865
      if (context != NULL && !is_device_in_fstab (device, NULL))
 
6866
        {
 
6867
          action_id = "org.freedesktop.udisks.filesystem-unmount-others";
 
6868
        }
 
6869
    }
 
6870
  else
 
6871
    {
 
6872
      uid_t uid;
 
6873
      daemon_local_get_uid (device->priv->daemon, &uid, context);
 
6874
      if (context != NULL && uid_of_mount != uid)
 
6875
        {
 
6876
          action_id = "org.freedesktop.udisks.filesystem-unmount-others";
 
6877
        }
 
6878
    }
 
6879
 
 
6880
  daemon_local_check_auth (device->priv->daemon,
 
6881
                           device,
 
6882
                           action_id,
 
6883
                           "FilesystemUnmount",
 
6884
                           TRUE,
 
6885
                           device_filesystem_unmount_authorized_cb,
 
6886
                           context,
 
6887
                           1,
 
6888
                           g_strdupv (options),
 
6889
                           g_strfreev);
 
6890
 
 
6891
 out:
 
6892
  return TRUE;
 
6893
}
 
6894
 
 
6895
/*--------------------------------------------------------------------------------------------------------------*/
 
6896
 
 
6897
static uid_t
 
6898
get_uid_for_pid (pid_t pid)
 
6899
{
 
6900
  uid_t ret;
 
6901
  char proc_name[32];
 
6902
  struct stat statbuf;
 
6903
 
 
6904
  ret = 0;
 
6905
 
 
6906
  snprintf (proc_name, sizeof(proc_name), "/proc/%d/stat", pid);
 
6907
  if (stat (proc_name, &statbuf) == 0)
 
6908
    {
 
6909
      ret = statbuf.st_uid;
 
6910
    }
 
6911
 
 
6912
  return ret;
 
6913
}
 
6914
 
 
6915
static char *
 
6916
get_command_line_for_pid (pid_t pid)
 
6917
{
 
6918
  char proc_name[32];
 
6919
  char *buf;
 
6920
  gsize len;
 
6921
  char *ret;
 
6922
  unsigned int n;
 
6923
 
 
6924
  ret = NULL;
 
6925
 
 
6926
  snprintf (proc_name, sizeof(proc_name), "/proc/%d/cmdline", pid);
 
6927
  if (g_file_get_contents (proc_name, &buf, &len, NULL))
 
6928
    {
 
6929
      for (n = 0; n < len; n++)
 
6930
        {
 
6931
          if (buf[n] == '\0')
 
6932
            buf[n] = ' ';
 
6933
        }
 
6934
      g_strstrip (buf);
 
6935
      ret = buf;
 
6936
    }
 
6937
 
 
6938
  return ret;
 
6939
}
 
6940
 
 
6941
static void
 
6942
lsof_parse (const char *stdout,
 
6943
            GPtrArray *processes)
 
6944
{
 
6945
  int n;
 
6946
  char **tokens;
 
6947
 
 
6948
  tokens = g_strsplit (stdout, "\n", 0);
 
6949
  for (n = 0; tokens[n] != NULL; n++)
 
6950
    {
 
6951
      pid_t pid;
 
6952
      uid_t uid;
 
6953
      char *command_line;
 
6954
      GValue elem =
 
6955
        { 0 };
 
6956
 
 
6957
      if (strlen (tokens[n]) == 0)
 
6958
        continue;
 
6959
 
 
6960
      pid = strtol (tokens[n], NULL, 0);
 
6961
      uid = get_uid_for_pid (pid);
 
6962
      command_line = get_command_line_for_pid (pid);
 
6963
 
 
6964
      g_value_init (&elem, LSOF_DATA_STRUCT_TYPE);
 
6965
      g_value_take_boxed (&elem, dbus_g_type_specialized_construct (LSOF_DATA_STRUCT_TYPE));
 
6966
      dbus_g_type_struct_set (&elem, 0, pid, 1, uid, 2, command_line != NULL ? command_line : "", G_MAXUINT);
 
6967
      g_ptr_array_add (processes, g_value_get_boxed (&elem));
 
6968
 
 
6969
      g_free (command_line);
 
6970
    }
 
6971
  g_strfreev (tokens);
 
6972
}
 
6973
 
 
6974
static void
 
6975
filesystem_list_open_files_completed_cb (DBusGMethodInvocation *context,
 
6976
                                         Device *device,
 
6977
                                         gboolean job_was_cancelled,
 
6978
                                         int status,
 
6979
                                         const char *stderr,
 
6980
                                         const char *stdout,
 
6981
                                         gpointer user_data)
 
6982
{
 
6983
  if ((WEXITSTATUS (status) == 0 || WEXITSTATUS (status) == 1) && !job_was_cancelled)
 
6984
    {
 
6985
      GPtrArray *processes;
 
6986
 
 
6987
      processes = g_ptr_array_new ();
 
6988
      lsof_parse (stdout, processes);
 
6989
      dbus_g_method_return (context, processes);
 
6990
      g_ptr_array_foreach (processes, (GFunc) g_value_array_free, NULL);
 
6991
      g_ptr_array_free (processes, TRUE);
 
6992
    }
 
6993
  else
 
6994
    {
 
6995
      throw_error (context,
 
6996
                   ERROR_FAILED,
 
6997
                   "Error listing open files: lsof exited with exit code %d: %s",
 
6998
                   WEXITSTATUS (status),
 
6999
                   stderr);
 
7000
    }
 
7001
}
 
7002
 
 
7003
static void
 
7004
device_filesystem_list_open_files_authorized_cb (Daemon *daemon,
 
7005
                                                 Device *device,
 
7006
                                                 DBusGMethodInvocation *context,
 
7007
                                                 const gchar *action_id,
 
7008
                                                 guint num_user_data,
 
7009
                                                 gpointer *user_data_elements)
 
7010
{
 
7011
  int n;
 
7012
  char *argv[16];
 
7013
 
 
7014
  if (!device->priv->device_is_mounted || device->priv->device_mount_paths->len == 0)
 
7015
    {
 
7016
      throw_error (context, ERROR_FAILED, "Device is not mounted");
 
7017
      goto out;
 
7018
    }
 
7019
 
 
7020
  n = 0;
 
7021
  argv[n++] = "lsof";
 
7022
  argv[n++] = "-t";
 
7023
  argv[n++] = ((gchar **) device->priv->device_mount_paths->pdata)[0];
 
7024
  argv[n++] = NULL;
 
7025
 
 
7026
  if (!job_new (context, NULL, /* don't run this as a job */
 
7027
                FALSE, device, argv, NULL, filesystem_list_open_files_completed_cb, FALSE, NULL, NULL))
 
7028
    {
 
7029
      goto out;
 
7030
    }
 
7031
 
 
7032
 out:
 
7033
  ;
 
7034
}
 
7035
 
 
7036
gboolean
 
7037
device_filesystem_list_open_files (Device *device,
 
7038
                                   DBusGMethodInvocation *context)
 
7039
{
 
7040
  if (!device->priv->device_is_mounted || device->priv->device_mount_paths->len == 0)
 
7041
    {
 
7042
      throw_error (context, ERROR_FAILED, "Device is not mounted");
 
7043
      goto out;
 
7044
    }
 
7045
 
 
7046
  daemon_local_check_auth (device->priv->daemon,
 
7047
                           device,
 
7048
                           device->priv->device_is_system_internal ? "org.freedesktop.udisks.filesystem-lsof-system-internal"
 
7049
                           : "org.freedesktop.udisks.filesystem-lsof",
 
7050
                           "FilesystemListOpenFiles",
 
7051
                           TRUE,
 
7052
                           device_filesystem_list_open_files_authorized_cb,
 
7053
                           context,
 
7054
                           0);
 
7055
 
 
7056
 out:
 
7057
  return TRUE;
 
7058
}
 
7059
 
 
7060
/*--------------------------------------------------------------------------------------------------------------*/
 
7061
 
 
7062
static void
 
7063
drive_eject_completed_cb (DBusGMethodInvocation *context,
 
7064
                          Device *device,
 
7065
                          gboolean job_was_cancelled,
 
7066
                          int status,
 
7067
                          const char *stderr,
 
7068
                          const char *stdout,
 
7069
                          gpointer user_data)
 
7070
{
 
7071
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
7072
    {
 
7073
      /* TODO: probably wait for has_media to change to FALSE */
 
7074
      if (context != NULL)
 
7075
          dbus_g_method_return (context);
 
7076
    }
 
7077
  else
 
7078
    {
 
7079
      if (job_was_cancelled)
 
7080
        {
 
7081
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
7082
        }
 
7083
      else
 
7084
        {
 
7085
          throw_error (context,
 
7086
                       ERROR_FAILED,
 
7087
                       "Error ejecting: eject exited with exit code %d: %s",
 
7088
                       WEXITSTATUS (status),
 
7089
                       stderr);
 
7090
        }
 
7091
    }
 
7092
}
 
7093
 
 
7094
static void
 
7095
device_drive_eject_authorized_cb (Daemon *daemon,
 
7096
                                  Device *device,
 
7097
                                  DBusGMethodInvocation *context,
 
7098
                                  const gchar *action_id,
 
7099
                                  guint num_user_data,
 
7100
                                  gpointer *user_data_elements)
 
7101
{
 
7102
  gchar **options = user_data_elements[0];
 
7103
  int n;
 
7104
  char *argv[16];
 
7105
  GError *error;
 
7106
  gboolean unmount = FALSE;
 
7107
 
 
7108
  error = NULL;
 
7109
 
 
7110
  if (!device->priv->device_is_drive)
 
7111
    {
 
7112
      throw_error (context, ERROR_FAILED, "Device is not a drive");
 
7113
      goto out;
 
7114
    }
 
7115
 
 
7116
  if (!device->priv->device_is_media_available)
 
7117
    {
 
7118
      throw_error (context, ERROR_FAILED, "No media in drive");
 
7119
      goto out;
 
7120
    }
 
7121
 
 
7122
  for (n = 0; options[n] != NULL; n++)
 
7123
    {
 
7124
      const char *option = options[n];
 
7125
      if (strcmp ("unmount", option) == 0)
 
7126
        {
 
7127
          unmount = TRUE;
 
7128
        }
 
7129
      else
 
7130
        {
 
7131
          throw_error (context, ERROR_INVALID_OPTION, "Unknown option %s", option);
 
7132
          goto out;
 
7133
        }
 
7134
    }
 
7135
 
 
7136
  /* If we specify the unmount option, don't check if the device is mounted */
 
7137
  if (device_local_is_busy (device, TRUE, !unmount, &error))
 
7138
    {
 
7139
      throw_error (context, ERROR_BUSY, error->message);
 
7140
      g_error_free (error);
 
7141
      goto out;
 
7142
    }
 
7143
 
 
7144
  /* eject already unmounts the file systems on the ejected drive, so we do not
 
7145
   * need any particular handling of the unmount flag here */
 
7146
  n = 0;
 
7147
  argv[n++] = "eject";
 
7148
  argv[n++] = device->priv->device_file;
 
7149
  argv[n++] = NULL;
 
7150
 
 
7151
  if (!job_new (context, "DriveEject", FALSE, device, argv, NULL, drive_eject_completed_cb, FALSE, NULL, NULL))
 
7152
    {
 
7153
      goto out;
 
7154
    }
 
7155
 
 
7156
 out:
 
7157
  ;
 
7158
}
 
7159
 
 
7160
gboolean
 
7161
device_drive_eject (Device *device,
 
7162
                    char **options,
 
7163
                    DBusGMethodInvocation *context)
 
7164
{
 
7165
  if (!device->priv->device_is_drive)
 
7166
    {
 
7167
      throw_error (context, ERROR_FAILED, "Device is not a drive");
 
7168
      goto out;
 
7169
    }
 
7170
 
 
7171
  if (!device->priv->device_is_media_available)
 
7172
    {
 
7173
      throw_error (context, ERROR_FAILED, "No media in drive");
 
7174
      goto out;
 
7175
    }
 
7176
 
 
7177
  daemon_local_check_auth (device->priv->daemon,
 
7178
                           device,
 
7179
                           context ? "org.freedesktop.udisks.drive-eject" : NULL,
 
7180
                           "DriveEject",
 
7181
                           TRUE,
 
7182
                           device_drive_eject_authorized_cb,
 
7183
                           context,
 
7184
                           1,
 
7185
                           g_strdupv (options),
 
7186
                           g_strfreev);
 
7187
 
 
7188
 out:
 
7189
  return TRUE;
 
7190
}
 
7191
 
 
7192
/*--------------------------------------------------------------------------------------------------------------*/
 
7193
 
 
7194
static void
 
7195
drive_detach_completed_cb (DBusGMethodInvocation *context,
 
7196
                           Device *device,
 
7197
                           gboolean job_was_cancelled,
 
7198
                           int status,
 
7199
                           const char *stderr,
 
7200
                           const char *stdout,
 
7201
                           gpointer user_data)
 
7202
{
 
7203
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
7204
    {
 
7205
      /* TODO: probably wait for has_media to change to FALSE */
 
7206
      dbus_g_method_return (context);
 
7207
    }
 
7208
  else
 
7209
    {
 
7210
      if (job_was_cancelled)
 
7211
        {
 
7212
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
7213
        }
 
7214
      else
 
7215
        {
 
7216
          throw_error (context,
 
7217
                       ERROR_FAILED,
 
7218
                       "Error detaching: helper exited with exit code %d: %s",
 
7219
                       WEXITSTATUS (status),
 
7220
                       stderr);
 
7221
        }
 
7222
    }
 
7223
}
 
7224
 
 
7225
static void
 
7226
device_drive_detach_authorized_cb (Daemon *daemon,
 
7227
                                   Device *device,
 
7228
                                   DBusGMethodInvocation *context,
 
7229
                                   const gchar *action_id,
 
7230
                                   guint num_user_data,
 
7231
                                   gpointer *user_data_elements)
 
7232
{
 
7233
  gchar **options = user_data_elements[0];
 
7234
  int n;
 
7235
  char *argv[16];
 
7236
  GError *error;
 
7237
 
 
7238
  error = NULL;
 
7239
 
 
7240
  if (!device->priv->device_is_drive)
 
7241
    {
 
7242
      throw_error (context, ERROR_FAILED, "Device is not a drive");
 
7243
      goto out;
 
7244
    }
 
7245
 
 
7246
  if (!device->priv->drive_can_detach)
 
7247
    {
 
7248
      throw_error (context, ERROR_FAILED, "Device is not detachable");
 
7249
      goto out;
 
7250
    }
 
7251
 
 
7252
  if (device_local_is_busy (device, TRUE, TRUE, &error))
 
7253
    {
 
7254
      dbus_g_method_return_error (context, error);
 
7255
      g_error_free (error);
 
7256
      goto out;
 
7257
    }
 
7258
 
 
7259
  for (n = 0; options[n] != NULL; n++)
 
7260
    {
 
7261
      const char *option = options[n];
 
7262
      throw_error (context, ERROR_INVALID_OPTION, "Unknown option %s", option);
 
7263
      goto out;
 
7264
    }
 
7265
 
 
7266
  n = 0;
 
7267
  argv[n++] = "udisks-helper-drive-detach";
 
7268
  argv[n++] = device->priv->device_file;
 
7269
  argv[n++] = NULL;
 
7270
 
 
7271
  if (!job_new (context, "DriveDetach", FALSE, device, argv, NULL, drive_detach_completed_cb, FALSE, NULL, NULL))
 
7272
    {
 
7273
      goto out;
 
7274
    }
 
7275
 
 
7276
 out:
 
7277
  ;
 
7278
}
 
7279
 
 
7280
gboolean
 
7281
device_drive_detach (Device *device,
 
7282
                     char **options,
 
7283
                     DBusGMethodInvocation *context)
 
7284
{
 
7285
  if (!device->priv->device_is_drive)
 
7286
    {
 
7287
      throw_error (context, ERROR_FAILED, "Device is not a drive");
 
7288
      goto out;
 
7289
    }
 
7290
 
 
7291
  if (!device->priv->drive_can_detach)
 
7292
    {
 
7293
      throw_error (context, ERROR_FAILED, "Device is not detachable");
 
7294
      goto out;
 
7295
    }
 
7296
 
 
7297
  daemon_local_check_auth (device->priv->daemon,
 
7298
                           device,
 
7299
                           "org.freedesktop.udisks.drive-detach",
 
7300
                           "DriveDetach",
 
7301
                           TRUE,
 
7302
                           device_drive_detach_authorized_cb,
 
7303
                           context,
 
7304
                           1,
 
7305
                           g_strdupv (options),
 
7306
                           g_strfreev);
 
7307
 
 
7308
 out:
 
7309
  return TRUE;
 
7310
}
 
7311
 
 
7312
/*--------------------------------------------------------------------------------------------------------------*/
 
7313
 
 
7314
static void
 
7315
filesystem_check_completed_cb (DBusGMethodInvocation *context,
 
7316
                               Device *device,
 
7317
                               gboolean job_was_cancelled,
 
7318
                               int status,
 
7319
                               const char *stderr,
 
7320
                               const char *stdout,
 
7321
                               gpointer user_data)
 
7322
{
 
7323
  if (WIFEXITED (status) && !job_was_cancelled)
 
7324
    {
 
7325
      int rc;
 
7326
      gboolean fs_is_clean;
 
7327
 
 
7328
      fs_is_clean = FALSE;
 
7329
 
 
7330
      rc = WEXITSTATUS (status);
 
7331
      if ((rc == 0) || (((rc & 1) != 0) && ((rc & 4) == 0)))
 
7332
        {
 
7333
          fs_is_clean = TRUE;
 
7334
        }
 
7335
 
 
7336
      dbus_g_method_return (context, fs_is_clean);
 
7337
    }
 
7338
  else
 
7339
    {
 
7340
      if (job_was_cancelled)
 
7341
        {
 
7342
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
7343
        }
 
7344
      else
 
7345
        {
 
7346
          throw_error (context,
 
7347
                       ERROR_FAILED,
 
7348
                       "Error fsck'ing: fsck exited with exit code %d: %s",
 
7349
                       WEXITSTATUS (status),
 
7350
                       stderr);
 
7351
        }
 
7352
    }
 
7353
}
 
7354
 
 
7355
static void
 
7356
device_filesystem_check_authorized_cb (Daemon *daemon,
 
7357
                                       Device *device,
 
7358
                                       DBusGMethodInvocation *context,
 
7359
                                       const gchar *action_id,
 
7360
                                       guint num_user_data,
 
7361
                                       gpointer *user_data_elements)
 
7362
{
 
7363
  /* TODO: use options! */
 
7364
  //gchar **options = user_data_elements[0];
 
7365
  int n;
 
7366
  char *argv[16];
 
7367
 
 
7368
  /* TODO: change when we have a file system that supports online fsck */
 
7369
  if (device->priv->device_is_mounted)
 
7370
    {
 
7371
      throw_error (context, ERROR_BUSY, "Device is mounted and no online capability in fsck tool for file system");
 
7372
      goto out;
 
7373
    }
 
7374
 
 
7375
  n = 0;
 
7376
  argv[n++] = "fsck";
 
7377
  argv[n++] = "-a";
 
7378
  argv[n++] = device->priv->device_file;
 
7379
  argv[n++] = NULL;
 
7380
 
 
7381
  if (!job_new (context, "FilesystemCheck", FALSE, device, argv, NULL, filesystem_check_completed_cb, FALSE, NULL, NULL))
 
7382
    {
 
7383
      goto out;
 
7384
    }
 
7385
 
 
7386
 out:
 
7387
  ;
 
7388
}
 
7389
 
 
7390
gboolean
 
7391
device_filesystem_check (Device *device,
 
7392
                         char **options,
 
7393
                         DBusGMethodInvocation *context)
 
7394
{
 
7395
  daemon_local_check_auth (device->priv->daemon,
 
7396
                           device,
 
7397
                           device->priv->device_is_system_internal ?
 
7398
                           "org.freedesktop.udisks.filesystem-check-system-internal" :
 
7399
                           "org.freedesktop.udisks.filesystem-check",
 
7400
                           "FilesystemCheck",
 
7401
                           TRUE,
 
7402
                           device_filesystem_check_authorized_cb,
 
7403
                           context,
 
7404
                           1,
 
7405
                           g_strdupv (options),
 
7406
                           g_strfreev);
 
7407
  return TRUE;
 
7408
}
 
7409
 
 
7410
/*--------------------------------------------------------------------------------------------------------------*/
 
7411
 
 
7412
static void
 
7413
partition_delete_completed_cb (DBusGMethodInvocation *context,
 
7414
                               Device *device,
 
7415
                               gboolean job_was_cancelled,
 
7416
                               int status,
 
7417
                               const char *stderr,
 
7418
                               const char *stdout,
 
7419
                               gpointer user_data)
 
7420
{
 
7421
  Device *enclosing_device = DEVICE (user_data);
 
7422
 
 
7423
  /* poke the kernel about the enclosing disk so we can reread the partitioning table */
 
7424
  device_generate_kernel_change_event (enclosing_device);
 
7425
 
 
7426
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
7427
    {
 
7428
      dbus_g_method_return (context);
 
7429
    }
 
7430
  else
 
7431
    {
 
7432
      if (job_was_cancelled)
 
7433
        {
 
7434
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
7435
        }
 
7436
      else
 
7437
        {
 
7438
          throw_error (context,
 
7439
                       ERROR_FAILED,
 
7440
                       "Error erasing: helper exited with exit code %d: %s",
 
7441
                       WEXITSTATUS (status),
 
7442
                       stderr);
 
7443
        }
 
7444
    }
 
7445
}
 
7446
 
 
7447
static void
 
7448
device_partition_delete_authorized_cb (Daemon *daemon,
 
7449
                                       Device *device,
 
7450
                                       DBusGMethodInvocation *context,
 
7451
                                       const gchar *action_id,
 
7452
                                       guint num_user_data,
 
7453
                                       gpointer *user_data_elements)
 
7454
{
 
7455
  gchar **options = user_data_elements[0];
 
7456
  int n;
 
7457
  int m;
 
7458
  char *argv[16];
 
7459
  GError *error;
 
7460
  char *offset_as_string;
 
7461
  char *size_as_string;
 
7462
  char *part_number_as_string;
 
7463
  Device *enclosing_device;
 
7464
  const gchar *partition_scheme;
 
7465
  gint partition_type;
 
7466
 
 
7467
  offset_as_string = NULL;
 
7468
  size_as_string = NULL;
 
7469
  part_number_as_string = NULL;
 
7470
  error = NULL;
 
7471
 
 
7472
  if (device_local_is_busy (device, FALSE, TRUE, &error))
 
7473
    {
 
7474
      dbus_g_method_return_error (context, error);
 
7475
      g_error_free (error);
 
7476
      goto out;
 
7477
    }
 
7478
 
 
7479
  if (!device->priv->device_is_partition)
 
7480
    {
 
7481
      throw_error (context, ERROR_FAILED, "Device is not a partition");
 
7482
      goto out;
 
7483
    }
 
7484
 
 
7485
  enclosing_device = daemon_local_find_by_object_path (device->priv->daemon, device->priv->partition_slave);
 
7486
  if (enclosing_device == NULL)
 
7487
    {
 
7488
      throw_error (context, ERROR_FAILED, "Cannot find enclosing device");
 
7489
      goto out;
 
7490
    }
 
7491
 
 
7492
  if (device_local_is_busy (enclosing_device, FALSE, TRUE, &error))
 
7493
    {
 
7494
      dbus_g_method_return_error (context, error);
 
7495
      g_error_free (error);
 
7496
      goto out;
 
7497
    }
 
7498
 
 
7499
  /* don't allow deleting an extended partition if we have any logical partitions */
 
7500
  partition_scheme = g_udev_device_get_property (device->priv->d, "UDISKS_PARTITION_SCHEME");
 
7501
  partition_type = g_udev_device_get_property_as_int (device->priv->d, "UDISKS_PARTITION_TYPE");
 
7502
  if (g_strcmp0 (partition_scheme, "mbr") == 0 && (partition_type == 0x05 || partition_type == 0x0f || partition_type
 
7503
                                                   == 0x85))
 
7504
    {
 
7505
      if (device_has_logical_partitions (enclosing_device))
 
7506
        {
 
7507
          throw_error (context, ERROR_FAILED, "Cannot delete extended partition while logical partitions exist");
 
7508
          goto out;
 
7509
        }
 
7510
    }
 
7511
 
 
7512
  offset_as_string = g_strdup_printf ("%" G_GINT64_FORMAT "", device->priv->partition_offset);
 
7513
  size_as_string = g_strdup_printf ("%" G_GINT64_FORMAT "", device->priv->partition_size);
 
7514
  part_number_as_string = g_strdup_printf ("%d", device->priv->partition_number);
 
7515
 
 
7516
  n = 0;
 
7517
  argv[n++] = "udisks-helper-delete-partition";
 
7518
  if (enclosing_device->priv->device_is_linux_dmmp)
 
7519
    argv[n++] = (gchar *) get_dmmp_device_node (enclosing_device);
 
7520
  else
 
7521
    argv[n++] = enclosing_device->priv->device_file;
 
7522
  argv[n++] = device->priv->device_file;
 
7523
  argv[n++] = offset_as_string;
 
7524
  argv[n++] = size_as_string;
 
7525
  argv[n++] = part_number_as_string;
 
7526
  for (m = 0; options[m] != NULL; m++)
 
7527
    {
 
7528
      if (n >= (int) sizeof(argv) - 1)
 
7529
        {
 
7530
          throw_error (context, ERROR_FAILED, "Too many options");
 
7531
          goto out;
 
7532
        }
 
7533
      /* the helper will validate each option */
 
7534
      argv[n++] = (char *) options[m];
 
7535
    }
 
7536
  argv[n++] = NULL;
 
7537
 
 
7538
  if (!job_new (context,
 
7539
                "PartitionDelete",
 
7540
                TRUE,
 
7541
                device,
 
7542
                argv,
 
7543
                NULL,
 
7544
                partition_delete_completed_cb,
 
7545
                FALSE,
 
7546
                g_object_ref (enclosing_device),
 
7547
                g_object_unref))
 
7548
    {
 
7549
      goto out;
 
7550
    }
 
7551
 
 
7552
 out:
 
7553
  g_free (offset_as_string);
 
7554
  g_free (size_as_string);
 
7555
  g_free (part_number_as_string);
 
7556
}
 
7557
 
 
7558
gboolean
 
7559
device_partition_delete (Device *device,
 
7560
                         char **options,
 
7561
                         DBusGMethodInvocation *context)
 
7562
{
 
7563
  daemon_local_check_auth (device->priv->daemon,
 
7564
                           device,
 
7565
                           device->priv->device_is_system_internal ? "org.freedesktop.udisks.change-system-internal"
 
7566
                           : "org.freedesktop.udisks.change",
 
7567
                           "PartitionDelete",
 
7568
                           TRUE,
 
7569
                           device_partition_delete_authorized_cb,
 
7570
                           context,
 
7571
                           1,
 
7572
                           g_strdupv (options),
 
7573
                           g_strfreev);
 
7574
  return TRUE;
 
7575
}
 
7576
 
 
7577
/*--------------------------------------------------------------------------------------------------------------*/
 
7578
 
 
7579
typedef struct
 
7580
{
 
7581
  FilesystemCreateHookFunc hook_func;
 
7582
  gpointer hook_user_data;
 
7583
} MkfsData;
 
7584
 
 
7585
static void
 
7586
mkfs_data_unref (MkfsData *data)
 
7587
{
 
7588
  g_free (data);
 
7589
}
 
7590
 
 
7591
static void
 
7592
filesystem_create_completed_cb (DBusGMethodInvocation *context,
 
7593
                                Device *device,
 
7594
                                gboolean job_was_cancelled,
 
7595
                                int status,
 
7596
                                const char *stderr,
 
7597
                                const char *stdout,
 
7598
                                gpointer user_data)
 
7599
{
 
7600
  MkfsData *data = user_data;
 
7601
 
 
7602
  /* poke the kernel so we can reread the data */
 
7603
  device_generate_kernel_change_event (device);
 
7604
 
 
7605
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
7606
    {
 
7607
      if (data->hook_func != NULL)
 
7608
        data->hook_func (context, device, TRUE, data->hook_user_data);
 
7609
      else
 
7610
        dbus_g_method_return (context);
 
7611
    }
 
7612
  else
 
7613
    {
 
7614
      if (job_was_cancelled)
 
7615
        {
 
7616
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
7617
        }
 
7618
      else if (WEXITSTATUS (status) == 3)
 
7619
        {
 
7620
          throw_error (context,
 
7621
                       ERROR_FILESYSTEM_TOOLS_MISSING,
 
7622
                       "Error creating file system: Cannot run mkfs: %s",
 
7623
                       stderr);
 
7624
        }
 
7625
      else
 
7626
        {
 
7627
          throw_error (context,
 
7628
                       ERROR_FAILED,
 
7629
                       "Error creating file system: helper exited with exit code %d: %s\n%s",
 
7630
                       WEXITSTATUS (status),
 
7631
                       stderr,
 
7632
                       stdout);
 
7633
        }
 
7634
 
 
7635
      if (data->hook_func != NULL)
 
7636
        data->hook_func (context, device, FALSE, data->hook_user_data);
 
7637
    }
 
7638
}
 
7639
 
 
7640
typedef struct
 
7641
{
 
7642
  int refcount;
 
7643
 
 
7644
  DBusGMethodInvocation *context;
 
7645
  Device *device;
 
7646
 
 
7647
  char *passphrase;
 
7648
 
 
7649
  char **options;
 
7650
  char *fstype;
 
7651
 
 
7652
  FilesystemCreateHookFunc mkfs_hook_func;
 
7653
  gpointer mkfs_hook_user_data;
 
7654
 
 
7655
  guint device_changed_signal_handler_id;
 
7656
  guint device_changed_timeout_id;
 
7657
} MkfsLuksData;
 
7658
 
 
7659
static MkfsLuksData *
 
7660
mkfse_data_ref (MkfsLuksData *data)
 
7661
{
 
7662
  data->refcount++;
 
7663
  return data;
 
7664
}
 
7665
 
 
7666
static void
 
7667
mkfse_data_unref (MkfsLuksData *data)
 
7668
{
 
7669
  data->refcount--;
 
7670
  if (data->refcount == 0)
 
7671
    {
 
7672
      if (data->passphrase != NULL)
 
7673
        {
 
7674
          memset (data->passphrase, '\0', strlen (data->passphrase));
 
7675
          g_free (data->passphrase);
 
7676
        }
 
7677
      if (data->device != NULL)
 
7678
        g_object_unref (data->device);
 
7679
      g_strfreev (data->options);
 
7680
      g_free (data->fstype);
 
7681
      g_free (data);
 
7682
    }
 
7683
}
 
7684
 
 
7685
static void
 
7686
filesystem_create_wait_for_cleartext_device_hook (DBusGMethodInvocation *context,
 
7687
                                                  Device *device,
 
7688
                                                  gpointer user_data)
 
7689
{
 
7690
  MkfsLuksData *data = user_data;
 
7691
 
 
7692
  if (device == NULL)
 
7693
    {
 
7694
      /* Dang, unlocking failed. The unlock method have already thrown an exception for us. */
 
7695
    }
 
7696
  else
 
7697
    {
 
7698
      /* We're unlocked.. awesome.. Now we can _finally_ create the file system.
 
7699
       * What a ride. We're returning to exactly to where we came from. Back to
 
7700
       * the source. Only the device is different.
 
7701
       */
 
7702
 
 
7703
      device_filesystem_create_internal (device,
 
7704
                                         data->fstype,
 
7705
                                         data->options,
 
7706
                                         data->mkfs_hook_func,
 
7707
                                         data->mkfs_hook_user_data,
 
7708
                                         data->context);
 
7709
      mkfse_data_unref (data);
 
7710
    }
 
7711
}
 
7712
 
 
7713
static void
 
7714
filesystem_create_wait_for_luks_device_changed_cb (Daemon *daemon,
 
7715
                                                   const char *object_path,
 
7716
                                                   gpointer user_data)
 
7717
{
 
7718
  MkfsLuksData *data = user_data;
 
7719
  Device *device;
 
7720
 
 
7721
  /* check if we're now a LUKS crypto device */
 
7722
  device = daemon_local_find_by_object_path (daemon, object_path);
 
7723
  if (device == data->device && (device->priv->id_usage != NULL && strcmp (device->priv->id_usage, "crypto") == 0)
 
7724
      && (device->priv->id_type != NULL && strcmp (device->priv->id_type, "crypto_LUKS") == 0))
 
7725
    {
 
7726
 
 
7727
      /* yay! we are now set up the corresponding cleartext device */
 
7728
 
 
7729
      device_luks_unlock_internal (data->device,
 
7730
                                   data->passphrase,
 
7731
                                   NULL,
 
7732
                                   filesystem_create_wait_for_cleartext_device_hook,
 
7733
                                   data,
 
7734
                                   data->context);
 
7735
 
 
7736
      g_signal_handler_disconnect (daemon, data->device_changed_signal_handler_id);
 
7737
      g_source_remove (data->device_changed_timeout_id);
 
7738
    }
 
7739
}
 
7740
 
 
7741
static gboolean
 
7742
filesystem_create_wait_for_luks_device_not_seen_cb (gpointer user_data)
 
7743
{
 
7744
  MkfsLuksData *data = user_data;
 
7745
 
 
7746
  throw_error (data->context,
 
7747
               ERROR_FAILED,
 
7748
               "Error creating luks encrypted file system: timeout (10s) waiting for luks device to show up");
 
7749
 
 
7750
  g_signal_handler_disconnect (data->device->priv->daemon, data->device_changed_signal_handler_id);
 
7751
  mkfse_data_unref (data);
 
7752
 
 
7753
  return FALSE;
 
7754
}
 
7755
 
 
7756
static void
 
7757
filesystem_create_create_luks_device_completed_cb (DBusGMethodInvocation *context,
 
7758
                                                   Device *device,
 
7759
                                                   gboolean job_was_cancelled,
 
7760
                                                   int status,
 
7761
                                                   const char *stderr,
 
7762
                                                   const char *stdout,
 
7763
                                                   gpointer user_data)
 
7764
{
 
7765
  MkfsLuksData *data = user_data;
 
7766
 
 
7767
  /* poke the kernel so we can reread the data (new uuid etc.) */
 
7768
  device_generate_kernel_change_event (device);
 
7769
 
 
7770
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
7771
    {
 
7772
 
 
7773
      /* OK! So we've got ourselves an luks device. Let's set it up so we can create a file
 
7774
       * system. Sit and wait for the change event to appear so we can setup with the right UUID.
 
7775
       */
 
7776
 
 
7777
      data->device_changed_signal_handler_id
 
7778
        = g_signal_connect_after (device->priv->daemon,
 
7779
                                  "device-changed",
 
7780
                                  (GCallback) filesystem_create_wait_for_luks_device_changed_cb,
 
7781
                                  mkfse_data_ref (data));
 
7782
 
 
7783
      /* set up timeout for error reporting if waiting failed
 
7784
       *
 
7785
       * (the signal handler and the timeout handler share the ref to data
 
7786
       * as one will cancel the other)
 
7787
       */
 
7788
      data->device_changed_timeout_id = g_timeout_add (10 * 1000,
 
7789
                                                       filesystem_create_wait_for_luks_device_not_seen_cb,
 
7790
                                                       data);
 
7791
 
 
7792
    }
 
7793
  else
 
7794
    {
 
7795
      if (job_was_cancelled)
 
7796
        {
 
7797
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
7798
        }
 
7799
      else
 
7800
        {
 
7801
          throw_error (context,
 
7802
                       ERROR_FAILED,
 
7803
                       "Error creating file system: cryptsetup exited with exit code %d: %s",
 
7804
                       WEXITSTATUS (status),
 
7805
                       stderr);
 
7806
        }
 
7807
    }
 
7808
}
 
7809
 
 
7810
static gboolean
 
7811
device_filesystem_create_internal (Device *device,
 
7812
                                   const char *fstype,
 
7813
                                   char **options,
 
7814
                                   FilesystemCreateHookFunc hook_func,
 
7815
                                   gpointer hook_user_data,
 
7816
                                   DBusGMethodInvocation *context)
 
7817
{
 
7818
  int n, m;
 
7819
  char *argv[128];
 
7820
  GError *error;
 
7821
  char *s;
 
7822
  char *options_for_stdin;
 
7823
  char *passphrase_stdin;
 
7824
  MkfsData *mkfs_data;
 
7825
 
 
7826
  options_for_stdin = NULL;
 
7827
  passphrase_stdin = NULL;
 
7828
  error = NULL;
 
7829
 
 
7830
  if (device_local_is_busy (device, TRUE, TRUE, &error))
 
7831
    {
 
7832
      dbus_g_method_return_error (context, error);
 
7833
      g_error_free (error);
 
7834
      goto out;
 
7835
    }
 
7836
 
 
7837
  if (strlen (fstype) == 0)
 
7838
    {
 
7839
      throw_error (context, ERROR_FAILED, "fstype not specified");
 
7840
      goto out;
 
7841
    }
 
7842
 
 
7843
  /* search for luks_encrypt=<passphrase> and do a detour if that's specified */
 
7844
  for (n = 0; options[n] != NULL; n++)
 
7845
    {
 
7846
      if (g_str_has_prefix (options[n], "luks_encrypt="))
 
7847
        {
 
7848
          MkfsLuksData *mkfse_data;
 
7849
 
 
7850
          /* So this is a request to create an luks device to put the
 
7851
           * file system on; save all options for mkfs (except luks_encrypt=) for
 
7852
           * later invocation once we have a cleartext device.
 
7853
           */
 
7854
 
 
7855
          mkfse_data = g_new0 (MkfsLuksData, 1);
 
7856
          mkfse_data->refcount = 1;
 
7857
          mkfse_data->context = context;
 
7858
          mkfse_data->device = g_object_ref (device);
 
7859
          mkfse_data->passphrase = g_strdup (options[n] + sizeof("luks_encrypt=") - 1);
 
7860
          mkfse_data->mkfs_hook_func = hook_func;
 
7861
          mkfse_data->mkfs_hook_user_data = hook_user_data;
 
7862
          mkfse_data->fstype = g_strdup (fstype);
 
7863
          mkfse_data->options = g_strdupv (options);
 
7864
          g_free (mkfse_data->options[n]);
 
7865
          for (m = n; mkfse_data->options[m] != NULL; m++)
 
7866
            {
 
7867
              mkfse_data->options[m] = mkfse_data->options[m + 1];
 
7868
            }
 
7869
 
 
7870
          passphrase_stdin = g_strdup_printf ("%s\n", mkfse_data->passphrase);
 
7871
 
 
7872
          n = 0;
 
7873
          argv[n++] = "cryptsetup";
 
7874
          argv[n++] = "-q";
 
7875
          argv[n++] = "luksFormat";
 
7876
          argv[n++] = device->priv->device_file;
 
7877
          argv[n++] = NULL;
 
7878
 
 
7879
          error = NULL;
 
7880
          if (!job_new (context,
 
7881
                        "LuksFormat",
 
7882
                        TRUE,
 
7883
                        device,
 
7884
                        argv,
 
7885
                        passphrase_stdin,
 
7886
                        filesystem_create_create_luks_device_completed_cb,
 
7887
                        FALSE,
 
7888
                        mkfse_data,
 
7889
                        (GDestroyNotify) mkfse_data_unref))
 
7890
            {
 
7891
              goto out;
 
7892
            }
 
7893
 
 
7894
          goto out;
 
7895
        }
 
7896
    }
 
7897
 
 
7898
  mkfs_data = g_new (MkfsData, 1);
 
7899
  mkfs_data->hook_func = hook_func;
 
7900
  mkfs_data->hook_user_data = hook_user_data;
 
7901
 
 
7902
  /* pass options on stdin as it may contain secrets */
 
7903
  s = g_strjoinv ("\n", options);
 
7904
  options_for_stdin = g_strconcat (s, "\n\n", NULL);
 
7905
  g_free (s);
 
7906
 
 
7907
  n = 0;
 
7908
  argv[n++] = "udisks-helper-mkfs";
 
7909
  argv[n++] = (char *) fstype;
 
7910
  argv[n++] = device->priv->device_file;
 
7911
  argv[n++] = device->priv->device_is_partition_table ? "1" : "0";
 
7912
  argv[n++] = NULL;
 
7913
 
 
7914
  if (!job_new (context,
 
7915
                "FilesystemCreate",
 
7916
                TRUE,
 
7917
                device,
 
7918
                argv,
 
7919
                options_for_stdin,
 
7920
                filesystem_create_completed_cb,
 
7921
                FALSE,
 
7922
                mkfs_data,
 
7923
                (GDestroyNotify) mkfs_data_unref))
 
7924
    {
 
7925
      goto out;
 
7926
    }
 
7927
 
 
7928
 out:
 
7929
  g_free (options_for_stdin);
 
7930
  if (passphrase_stdin != NULL)
 
7931
    {
 
7932
      memset (passphrase_stdin, '\0', strlen (passphrase_stdin));
 
7933
      g_free (passphrase_stdin);
 
7934
    }
 
7935
  return TRUE;
 
7936
}
 
7937
 
 
7938
static void
 
7939
device_filesystem_create_authorized_cb (Daemon *daemon,
 
7940
                                        Device *device,
 
7941
                                        DBusGMethodInvocation *context,
 
7942
                                        const gchar *action_id,
 
7943
                                        guint num_user_data,
 
7944
                                        gpointer *user_data_elements)
 
7945
{
 
7946
  const gchar *fstype = user_data_elements[0];
 
7947
  gchar **options = user_data_elements[1];
 
7948
  device_filesystem_create_internal (device, fstype, options, NULL, NULL, context);
 
7949
}
 
7950
 
 
7951
gboolean
 
7952
device_filesystem_create (Device *device,
 
7953
                          const char *fstype,
 
7954
                          char **options,
 
7955
                          DBusGMethodInvocation *context)
 
7956
{
 
7957
  daemon_local_check_auth (device->priv->daemon,
 
7958
                           device,
 
7959
                           device->priv->device_is_system_internal ? "org.freedesktop.udisks.change-system-internal"
 
7960
                           : "org.freedesktop.udisks.change",
 
7961
                           "FilesystemCreate",
 
7962
                           TRUE,
 
7963
                           device_filesystem_create_authorized_cb,
 
7964
                           context,
 
7965
                           2,
 
7966
                           g_strdup (fstype),
 
7967
                           g_free,
 
7968
                           g_strdupv (options),
 
7969
                           g_strfreev);
 
7970
  return TRUE;
 
7971
}
 
7972
 
 
7973
/*--------------------------------------------------------------------------------------------------------------*/
 
7974
 
 
7975
static void
 
7976
device_job_cancel_authorized_cb (Daemon *daemon,
 
7977
                                 Device *device,
 
7978
                                 DBusGMethodInvocation *context,
 
7979
                                 const gchar *action_id,
 
7980
                                 guint num_user_data,
 
7981
                                 gpointer *user_data_elements)
 
7982
{
 
7983
 
 
7984
  if (!device->priv->job_in_progress)
 
7985
    {
 
7986
      throw_error (context, ERROR_FAILED, "There is no job to cancel");
 
7987
      goto out;
 
7988
    }
 
7989
 
 
7990
  if (!device->priv->job_is_cancellable)
 
7991
    {
 
7992
      throw_error (context, ERROR_FAILED, "Job cannot be cancelled");
 
7993
      goto out;
 
7994
    }
 
7995
 
 
7996
  job_cancel (device);
 
7997
 
 
7998
  /* TODO: wait returning once the job is actually cancelled? */
 
7999
  dbus_g_method_return (context);
 
8000
 out:
 
8001
  ;
 
8002
}
 
8003
 
 
8004
gboolean
 
8005
device_job_cancel (Device *device,
 
8006
                   DBusGMethodInvocation *context)
 
8007
{
 
8008
  uid_t uid;
 
8009
  const gchar *action_id;
 
8010
 
 
8011
  if (!device->priv->job_in_progress)
 
8012
    {
 
8013
      throw_error (context, ERROR_FAILED, "There is no job to cancel");
 
8014
      goto out;
 
8015
    }
 
8016
 
 
8017
  if (!device->priv->job_is_cancellable)
 
8018
    {
 
8019
      throw_error (context, ERROR_FAILED, "Job cannot be cancelled");
 
8020
      goto out;
 
8021
    }
 
8022
 
 
8023
  daemon_local_get_uid (device->priv->daemon, &uid, context);
 
8024
 
 
8025
  action_id = NULL;
 
8026
  if (device->priv->job_initiated_by_uid != uid)
 
8027
    {
 
8028
      action_id = "org.freedesktop.udisks.cancel-job-others";
 
8029
    }
 
8030
 
 
8031
  daemon_local_check_auth (device->priv->daemon,
 
8032
                           device,
 
8033
                           action_id,
 
8034
                           "JobCancel",
 
8035
                           TRUE,
 
8036
                           device_job_cancel_authorized_cb,
 
8037
                           context,
 
8038
                           0);
 
8039
 
 
8040
 out:
 
8041
  return TRUE;
 
8042
}
 
8043
 
 
8044
/*--------------------------------------------------------------------------------------------------------------*/
 
8045
 
 
8046
typedef struct
 
8047
{
 
8048
  int refcount;
 
8049
 
 
8050
  guint device_added_signal_handler_id;
 
8051
  guint device_added_timeout_id;
 
8052
 
 
8053
  DBusGMethodInvocation *context;
 
8054
  Device *device;
 
8055
  guint64 offset;
 
8056
  guint64 size;
 
8057
 
 
8058
  guint64 created_offset;
 
8059
  guint64 created_size;
 
8060
 
 
8061
  char *fstype;
 
8062
  char **fsoptions;
 
8063
 
 
8064
} CreatePartitionData;
 
8065
 
 
8066
static CreatePartitionData *
 
8067
partition_create_data_new (DBusGMethodInvocation *context,
 
8068
                           Device *device,
 
8069
                           guint64 offset,
 
8070
                           guint64 size,
 
8071
                           const char *fstype,
 
8072
                           char **fsoptions)
 
8073
{
 
8074
  CreatePartitionData *data;
 
8075
 
 
8076
  data = g_new0 (CreatePartitionData, 1);
 
8077
  data->refcount = 1;
 
8078
 
 
8079
  data->context = context;
 
8080
  data->device = g_object_ref (device);
 
8081
  data->offset = offset;
 
8082
  data->size = size;
 
8083
  data->fstype = g_strdup (fstype);
 
8084
  data->fsoptions = g_strdupv (fsoptions);
 
8085
 
 
8086
  return data;
 
8087
}
 
8088
 
 
8089
static CreatePartitionData *
 
8090
partition_create_data_ref (CreatePartitionData *data)
 
8091
{
 
8092
  data->refcount++;
 
8093
  return data;
 
8094
}
 
8095
 
 
8096
static void
 
8097
partition_create_data_unref (CreatePartitionData *data)
 
8098
{
 
8099
  data->refcount--;
 
8100
  if (data->refcount == 0)
 
8101
    {
 
8102
      g_object_unref (data->device);
 
8103
      g_free (data->fstype);
 
8104
      g_strfreev (data->fsoptions);
 
8105
      g_free (data);
 
8106
    }
 
8107
}
 
8108
 
 
8109
static void
 
8110
partition_create_filesystem_create_hook (DBusGMethodInvocation *context,
 
8111
                                         Device *device,
 
8112
                                         gboolean filesystem_create_succeeded,
 
8113
                                         gpointer user_data)
 
8114
{
 
8115
  if (!filesystem_create_succeeded)
 
8116
    {
 
8117
      /* dang.. FilesystemCreate already reported an error */
 
8118
    }
 
8119
  else
 
8120
    {
 
8121
      /* it worked.. */
 
8122
      dbus_g_method_return (context, device->priv->object_path);
 
8123
    }
 
8124
}
 
8125
 
 
8126
static void
 
8127
partition_create_found_device (Device *device,
 
8128
                               CreatePartitionData *data)
 
8129
{
 
8130
  if (strlen (data->fstype) > 0)
 
8131
    {
 
8132
      device_filesystem_create_internal (device,
 
8133
                                         data->fstype,
 
8134
                                         data->fsoptions,
 
8135
                                         partition_create_filesystem_create_hook,
 
8136
                                         NULL,
 
8137
                                         data->context);
 
8138
    }
 
8139
  else
 
8140
    {
 
8141
      dbus_g_method_return (data->context, device->priv->object_path);
 
8142
    }
 
8143
}
 
8144
 
 
8145
static void
 
8146
partition_create_device_added_cb (Daemon *daemon,
 
8147
                                  const char *object_path,
 
8148
                                  gpointer user_data)
 
8149
{
 
8150
  CreatePartitionData *data = user_data;
 
8151
  Device *device;
 
8152
 
 
8153
  /* check the device added is the partition we've created */
 
8154
  device = daemon_local_find_by_object_path (daemon, object_path);
 
8155
  if (device != NULL && device->priv->device_is_partition && strcmp (device->priv->partition_slave,
 
8156
                                                                     data->device->priv->object_path) == 0
 
8157
      && data->created_offset == device->priv->partition_offset && data->created_size == device->priv->partition_size)
 
8158
    {
 
8159
 
 
8160
      /* yay! it is.. now create the file system if requested */
 
8161
      partition_create_found_device (device, data);
 
8162
 
 
8163
      g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id);
 
8164
      g_source_remove (data->device_added_timeout_id);
 
8165
      partition_create_data_unref (data);
 
8166
    }
 
8167
}
 
8168
 
 
8169
static gboolean
 
8170
partition_create_device_not_seen_cb (gpointer user_data)
 
8171
{
 
8172
  CreatePartitionData *data = user_data;
 
8173
 
 
8174
  throw_error (data->context, ERROR_FAILED, "Error creating partition: timeout (10s) waiting for partition to show up");
 
8175
 
 
8176
  g_signal_handler_disconnect (data->device->priv->daemon, data->device_added_signal_handler_id);
 
8177
  partition_create_data_unref (data);
 
8178
 
 
8179
  return FALSE;
 
8180
}
 
8181
 
 
8182
static void
 
8183
partition_create_completed_cb (DBusGMethodInvocation *context,
 
8184
                               Device *device,
 
8185
                               gboolean job_was_cancelled,
 
8186
                               int status,
 
8187
                               const char *stderr,
 
8188
                               const char *stdout,
 
8189
                               gpointer user_data)
 
8190
{
 
8191
  CreatePartitionData *data = user_data;
 
8192
 
 
8193
  /* poke the kernel so we can reread the data */
 
8194
  device_generate_kernel_change_event (device);
 
8195
 
 
8196
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
8197
    {
 
8198
      int n;
 
8199
      int m;
 
8200
      guint64 offset;
 
8201
      guint64 size;
 
8202
      char **tokens;
 
8203
 
 
8204
      /* Find the
 
8205
       *
 
8206
       *   job-create-partition-offset:
 
8207
       *   job-create-partition-size:
 
8208
       *
 
8209
       * lines and parse the new start and end. We need this
 
8210
       * for waiting on the created partition (since the requested
 
8211
       * start and size passed may not be honored due to disk/cylinder/sector
 
8212
       * alignment reasons).
 
8213
       */
 
8214
      offset = 0;
 
8215
      size = 0;
 
8216
      m = 0;
 
8217
      tokens = g_strsplit (stderr, "\n", 0);
 
8218
      for (n = 0; tokens[n] != NULL; n++)
 
8219
        {
 
8220
          char *line = tokens[n];
 
8221
          char *endp;
 
8222
 
 
8223
          if (m == 2)
 
8224
            break;
 
8225
 
 
8226
          if (g_str_has_prefix (line, "job-create-partition-offset: "))
 
8227
            {
 
8228
              offset = strtoll (line + sizeof("job-create-partition-offset: ") - 1, &endp, 10);
 
8229
              if (*endp == '\0')
 
8230
                m++;
 
8231
            }
 
8232
          else if (g_str_has_prefix (line, "job-create-partition-size: "))
 
8233
            {
 
8234
              size = strtoll (line + sizeof("job-create-partition-size: ") - 1, &endp, 10);
 
8235
              if (*endp == '\0')
 
8236
                m++;
 
8237
            }
 
8238
        }
 
8239
      g_strfreev (tokens);
 
8240
 
 
8241
      if (m != 2)
 
8242
        {
 
8243
          throw_error (context, ERROR_FAILED, "Error creating partition: internal error, expected to find new "
 
8244
                       "start and end but m=%d", m);
 
8245
        }
 
8246
      else
 
8247
        {
 
8248
          gboolean found_device;
 
8249
          GList *devices;
 
8250
          GList *l;
 
8251
 
 
8252
          data->created_offset = offset;
 
8253
          data->created_size = size;
 
8254
 
 
8255
          /* check if the device is already there */
 
8256
          found_device = FALSE;
 
8257
          devices = daemon_local_get_all_devices (device->priv->daemon);
 
8258
          for (l = devices; l != NULL; l = l->next)
 
8259
            {
 
8260
              Device *d = DEVICE (l->data);
 
8261
 
 
8262
              if (d->priv->device_is_partition && strcmp (d->priv->partition_slave, data->device->priv->object_path)
 
8263
                  == 0 && data->created_offset == d->priv->partition_offset && data->created_size
 
8264
                  == d->priv->partition_size)
 
8265
                {
 
8266
                  /* yay! it is.. now create the file system if requested */
 
8267
                  partition_create_found_device (d, data);
 
8268
                  found_device = TRUE;
 
8269
                  break;
 
8270
                }
 
8271
            }
 
8272
 
 
8273
          if (!found_device)
 
8274
            {
 
8275
              /* otherwise sit around and wait for the new partition to appear */
 
8276
              data->device_added_signal_handler_id
 
8277
                = g_signal_connect_after (device->priv->daemon,
 
8278
                                          "device-added",
 
8279
                                          (GCallback) partition_create_device_added_cb,
 
8280
                                          partition_create_data_ref (data));
 
8281
 
 
8282
              /* set up timeout for error reporting if waiting failed
 
8283
               *
 
8284
               * (the signal handler and the timeout handler share the ref to data
 
8285
               * as one will cancel the other)
 
8286
               */
 
8287
              data->device_added_timeout_id = g_timeout_add (10 * 1000, partition_create_device_not_seen_cb, data);
 
8288
            }
 
8289
        }
 
8290
    }
 
8291
  else
 
8292
    {
 
8293
      if (job_was_cancelled)
 
8294
        {
 
8295
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
8296
        }
 
8297
      else
 
8298
        {
 
8299
          throw_error (context,
 
8300
                       ERROR_FAILED,
 
8301
                       "Error creating partition: helper exited with exit code %d: %s",
 
8302
                       WEXITSTATUS (status),
 
8303
                       stderr);
 
8304
        }
 
8305
    }
 
8306
}
 
8307
 
 
8308
static void
 
8309
device_partition_create_authorized_cb (Daemon *daemon,
 
8310
                                       Device *device,
 
8311
                                       DBusGMethodInvocation *context,
 
8312
                                       const gchar *action_id,
 
8313
                                       guint num_user_data,
 
8314
                                       gpointer *user_data_elements)
 
8315
{
 
8316
  guint64 offset = *((guint64*) user_data_elements[0]);
 
8317
  guint64 size = *((guint64*) user_data_elements[1]);
 
8318
  ;
 
8319
  const char *type = user_data_elements[2];
 
8320
  const char *label = user_data_elements[3];
 
8321
  char **flags = user_data_elements[4];
 
8322
  char **options = user_data_elements[5];
 
8323
  const char *fstype = user_data_elements[6];
 
8324
  char **fsoptions = user_data_elements[7];
 
8325
  int n;
 
8326
  int m;
 
8327
  char *argv[128];
 
8328
  GError *error;
 
8329
  char *offset_as_string;
 
8330
  char *size_as_string;
 
8331
  char *flags_as_string;
 
8332
 
 
8333
  offset_as_string = NULL;
 
8334
  size_as_string = NULL;
 
8335
  flags_as_string = NULL;
 
8336
  error = NULL;
 
8337
 
 
8338
  if (!device->priv->device_is_partition_table)
 
8339
    {
 
8340
      throw_error (context, ERROR_FAILED, "Device is not partitioned");
 
8341
      goto out;
 
8342
    }
 
8343
 
 
8344
  if (device_local_is_busy (device, FALSE, TRUE, &error))
 
8345
    {
 
8346
      dbus_g_method_return_error (context, error);
 
8347
      g_error_free (error);
 
8348
      goto out;
 
8349
    }
 
8350
 
 
8351
  /* partutil.c / libparted will check there are no partitions in the requested slice */
 
8352
 
 
8353
  offset_as_string = g_strdup_printf ("%" G_GINT64_FORMAT "", offset);
 
8354
  size_as_string = g_strdup_printf ("%" G_GINT64_FORMAT "", size);
 
8355
  /* TODO: check that neither of the flags include ',' */
 
8356
  flags_as_string = g_strjoinv (",", flags);
 
8357
 
 
8358
  n = 0;
 
8359
  argv[n++] = "udisks-helper-create-partition";
 
8360
  if (device->priv->device_is_linux_dmmp)
 
8361
    argv[n++] = (gchar *) get_dmmp_device_node (device);
 
8362
  else
 
8363
    argv[n++] = device->priv->device_file;
 
8364
  argv[n++] = offset_as_string;
 
8365
  argv[n++] = size_as_string;
 
8366
  argv[n++] = (char *) type;
 
8367
  argv[n++] = (char *) label;
 
8368
  argv[n++] = (char *) flags_as_string;
 
8369
  for (m = 0; options[m] != NULL; m++)
 
8370
    {
 
8371
      if (n >= (int) sizeof(argv) - 1)
 
8372
        {
 
8373
          throw_error (context, ERROR_FAILED, "Too many options");
 
8374
          goto out;
 
8375
        }
 
8376
      /* the helper will validate each option */
 
8377
      argv[n++] = (char *) options[m];
 
8378
    }
 
8379
  argv[n++] = NULL;
 
8380
 
 
8381
  if (!job_new (context,
 
8382
                "PartitionCreate",
 
8383
                TRUE,
 
8384
                device,
 
8385
                argv,
 
8386
                NULL,
 
8387
                partition_create_completed_cb,
 
8388
                FALSE,
 
8389
                partition_create_data_new (context, device, offset, size, fstype, fsoptions),
 
8390
                (GDestroyNotify) partition_create_data_unref))
 
8391
    {
 
8392
      goto out;
 
8393
    }
 
8394
 
 
8395
 out:
 
8396
  g_free (offset_as_string);
 
8397
  g_free (size_as_string);
 
8398
  g_free (flags_as_string);
 
8399
}
 
8400
 
 
8401
gboolean
 
8402
device_partition_create (Device *device,
 
8403
                         guint64 offset,
 
8404
                         guint64 size,
 
8405
                         const char *type,
 
8406
                         const char *label,
 
8407
                         char **flags,
 
8408
                         char **options,
 
8409
                         const char *fstype,
 
8410
                         char **fsoptions,
 
8411
                         DBusGMethodInvocation *context)
 
8412
{
 
8413
  if (!device->priv->device_is_partition_table)
 
8414
    {
 
8415
      throw_error (context, ERROR_FAILED, "Device is not partitioned");
 
8416
      goto out;
 
8417
    }
 
8418
 
 
8419
  daemon_local_check_auth (device->priv->daemon,
 
8420
                           device,
 
8421
                           device->priv->device_is_system_internal ? "org.freedesktop.udisks.change-system-internal"
 
8422
                           : "org.freedesktop.udisks.change",
 
8423
                           "PartitionCreate",
 
8424
                           TRUE,
 
8425
                           device_partition_create_authorized_cb,
 
8426
                           context,
 
8427
                           8,
 
8428
                           g_memdup (&offset, sizeof(guint64)),
 
8429
                           g_free,
 
8430
                           g_memdup (&size, sizeof(guint64)),
 
8431
                           g_free,
 
8432
                           g_strdup (type),
 
8433
                           g_free,
 
8434
                           g_strdup (label),
 
8435
                           g_free,
 
8436
                           g_strdupv (flags),
 
8437
                           g_strfreev,
 
8438
                           g_strdupv (options),
 
8439
                           g_strfreev,
 
8440
                           g_strdup (fstype),
 
8441
                           g_free,
 
8442
                           g_strdupv (fsoptions),
 
8443
                           g_strfreev);
 
8444
 
 
8445
 out:
 
8446
  return TRUE;
 
8447
}
 
8448
 
 
8449
/*--------------------------------------------------------------------------------------------------------------*/
 
8450
 
 
8451
typedef struct
 
8452
{
 
8453
  DBusGMethodInvocation *context;
 
8454
  Device *device;
 
8455
  Device *enclosing_device;
 
8456
 
 
8457
  char *type;
 
8458
  char *label;
 
8459
  char **flags;
 
8460
} ModifyPartitionData;
 
8461
 
 
8462
static ModifyPartitionData *
 
8463
partition_modify_data_new (DBusGMethodInvocation *context,
 
8464
                           Device *device,
 
8465
                           Device *enclosing_device,
 
8466
                           const char *type,
 
8467
                           const char *label,
 
8468
                           char **flags)
 
8469
{
 
8470
  ModifyPartitionData *data;
 
8471
 
 
8472
  data = g_new0 (ModifyPartitionData, 1);
 
8473
 
 
8474
  data->context = context;
 
8475
  data->device = g_object_ref (device);
 
8476
  data->enclosing_device = g_object_ref (enclosing_device);
 
8477
  data->type = g_strdup (type);
 
8478
  data->label = g_strdup (label);
 
8479
  data->flags = g_strdupv (flags);
 
8480
 
 
8481
  return data;
 
8482
}
 
8483
 
 
8484
static void
 
8485
partition_modify_data_unref (ModifyPartitionData *data)
 
8486
{
 
8487
  g_object_unref (data->device);
 
8488
  g_object_unref (data->enclosing_device);
 
8489
  g_free (data->type);
 
8490
  g_free (data->label);
 
8491
  g_free (data->flags);
 
8492
  g_free (data);
 
8493
}
 
8494
 
 
8495
static void
 
8496
partition_modify_completed_cb (DBusGMethodInvocation *context,
 
8497
                               Device *device,
 
8498
                               gboolean job_was_cancelled,
 
8499
                               int status,
 
8500
                               const char *stderr,
 
8501
                               const char *stdout,
 
8502
                               gpointer user_data)
 
8503
{
 
8504
  ModifyPartitionData *data = user_data;
 
8505
 
 
8506
  /* poke the kernel so we can reread the data */
 
8507
  device_generate_kernel_change_event (data->enclosing_device);
 
8508
  device_generate_kernel_change_event (data->device);
 
8509
 
 
8510
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
8511
    {
 
8512
      /* update local copy, don't wait for the kernel */
 
8513
 
 
8514
      device_set_partition_type (device, data->type);
 
8515
      device_set_partition_label (device, data->label);
 
8516
      device_set_partition_flags (device, data->flags);
 
8517
 
 
8518
      drain_pending_changes (device, FALSE);
 
8519
 
 
8520
      dbus_g_method_return (context);
 
8521
 
 
8522
    }
 
8523
  else
 
8524
    {
 
8525
      if (job_was_cancelled)
 
8526
        {
 
8527
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
8528
        }
 
8529
      else
 
8530
        {
 
8531
          throw_error (context,
 
8532
                       ERROR_FAILED,
 
8533
                       "Error modifying partition: helper exited with exit code %d: %s",
 
8534
                       WEXITSTATUS (status),
 
8535
                       stderr);
 
8536
        }
 
8537
    }
 
8538
}
 
8539
 
 
8540
static void
 
8541
device_partition_modify_authorized_cb (Daemon *daemon,
 
8542
                                       Device *device,
 
8543
                                       DBusGMethodInvocation *context,
 
8544
                                       const gchar *action_id,
 
8545
                                       guint num_user_data,
 
8546
                                       gpointer *user_data_elements)
 
8547
{
 
8548
  const char *type = user_data_elements[0];
 
8549
  const char *label = user_data_elements[1];
 
8550
  char **flags = user_data_elements[2];
 
8551
  int n;
 
8552
  char *argv[128];
 
8553
  GError *error;
 
8554
  char *offset_as_string;
 
8555
  char *size_as_string;
 
8556
  char *flags_as_string;
 
8557
  Device *enclosing_device;
 
8558
 
 
8559
  offset_as_string = NULL;
 
8560
  size_as_string = NULL;
 
8561
  flags_as_string = NULL;
 
8562
  error = NULL;
 
8563
 
 
8564
  if (!device->priv->device_is_partition)
 
8565
    {
 
8566
      throw_error (context, ERROR_FAILED, "Device is not a partition");
 
8567
      goto out;
 
8568
    }
 
8569
 
 
8570
  enclosing_device = daemon_local_find_by_object_path (device->priv->daemon, device->priv->partition_slave);
 
8571
  if (enclosing_device == NULL)
 
8572
    {
 
8573
      throw_error (context, ERROR_FAILED, "Cannot find enclosing device");
 
8574
      goto out;
 
8575
    }
 
8576
 
 
8577
  if (device_local_is_busy (enclosing_device, FALSE, TRUE, &error))
 
8578
    {
 
8579
      dbus_g_method_return_error (context, error);
 
8580
      g_error_free (error);
 
8581
      goto out;
 
8582
    }
 
8583
 
 
8584
  if (strlen (type) == 0)
 
8585
    {
 
8586
      throw_error (context, ERROR_FAILED, "type not specified");
 
8587
      goto out;
 
8588
    }
 
8589
 
 
8590
  offset_as_string = g_strdup_printf ("%" G_GINT64_FORMAT "", device->priv->partition_offset);
 
8591
  size_as_string = g_strdup_printf ("%" G_GINT64_FORMAT "", device->priv->partition_size);
 
8592
  /* TODO: check that neither of the flags include ',' */
 
8593
  flags_as_string = g_strjoinv (",", flags);
 
8594
 
 
8595
  n = 0;
 
8596
  argv[n++] = "udisks-helper-modify-partition";
 
8597
  argv[n++] = enclosing_device->priv->device_file;
 
8598
  argv[n++] = offset_as_string;
 
8599
  argv[n++] = size_as_string;
 
8600
  argv[n++] = (char *) type;
 
8601
  argv[n++] = (char *) label;
 
8602
  argv[n++] = (char *) flags_as_string;
 
8603
  argv[n++] = NULL;
 
8604
 
 
8605
  if (!job_new (context,
 
8606
                "PartitionModify",
 
8607
                TRUE,
 
8608
                device,
 
8609
                argv,
 
8610
                NULL,
 
8611
                partition_modify_completed_cb,
 
8612
                FALSE,
 
8613
                partition_modify_data_new (context, device, enclosing_device, type, label, flags),
 
8614
                (GDestroyNotify) partition_modify_data_unref))
 
8615
    {
 
8616
      goto out;
 
8617
    }
 
8618
 
 
8619
 out:
 
8620
  g_free (offset_as_string);
 
8621
  g_free (size_as_string);
 
8622
  g_free (flags_as_string);
 
8623
}
 
8624
 
 
8625
gboolean
 
8626
device_partition_modify (Device *device,
 
8627
                         const char *type,
 
8628
                         const char *label,
 
8629
                         char **flags,
 
8630
                         DBusGMethodInvocation *context)
 
8631
{
 
8632
  if (!device->priv->device_is_partition)
 
8633
    {
 
8634
      throw_error (context, ERROR_FAILED, "Device is not a partition");
 
8635
      goto out;
 
8636
    }
 
8637
 
 
8638
  daemon_local_check_auth (device->priv->daemon,
 
8639
                           device,
 
8640
                           device->priv->device_is_system_internal ? "org.freedesktop.udisks.change-system-internal"
 
8641
                           : "org.freedesktop.udisks.change",
 
8642
                           "PartitionModify",
 
8643
                           TRUE,
 
8644
                           device_partition_modify_authorized_cb,
 
8645
                           context,
 
8646
                           3,
 
8647
                           g_strdup (type),
 
8648
                           g_free,
 
8649
                           g_strdup (label),
 
8650
                           g_free,
 
8651
                           g_strdupv (flags),
 
8652
                           g_strfreev);
 
8653
 
 
8654
 out:
 
8655
  return TRUE;
 
8656
}
 
8657
 
 
8658
/*--------------------------------------------------------------------------------------------------------------*/
 
8659
 
 
8660
typedef struct
 
8661
{
 
8662
  int refcount;
 
8663
 
 
8664
  guint device_changed_signal_handler_id;
 
8665
  guint device_changed_timeout_id;
 
8666
 
 
8667
  DBusGMethodInvocation *context;
 
8668
  Device *device;
 
8669
 
 
8670
  char *scheme;
 
8671
 
 
8672
} CreatePartitionTableData;
 
8673
 
 
8674
static CreatePartitionTableData *
 
8675
partition_table_create_data_new (DBusGMethodInvocation *context,
 
8676
                                 Device *device,
 
8677
                                 const char *scheme)
 
8678
{
 
8679
  CreatePartitionTableData *data;
 
8680
 
 
8681
  data = g_new0 (CreatePartitionTableData, 1);
 
8682
  data->refcount = 1;
 
8683
 
 
8684
  data->context = context;
 
8685
  data->device = g_object_ref (device);
 
8686
  data->scheme = g_strdup (scheme);
 
8687
 
 
8688
  return data;
 
8689
}
 
8690
 
 
8691
static CreatePartitionTableData *
 
8692
partition_table_create_data_ref (CreatePartitionTableData *data)
 
8693
{
 
8694
  data->refcount++;
 
8695
  return data;
 
8696
}
 
8697
 
 
8698
static void
 
8699
partition_table_create_data_unref (CreatePartitionTableData *data)
 
8700
{
 
8701
  data->refcount--;
 
8702
  if (data->refcount == 0)
 
8703
    {
 
8704
      g_object_unref (data->device);
 
8705
      g_free (data->scheme);
 
8706
      g_free (data);
 
8707
    }
 
8708
}
 
8709
 
 
8710
static void
 
8711
partition_table_create_device_changed_cb (Daemon *daemon,
 
8712
                                          const char *object_path,
 
8713
                                          gpointer user_data)
 
8714
{
 
8715
  CreatePartitionTableData *data = user_data;
 
8716
  Device *device;
 
8717
 
 
8718
  device = daemon_local_find_by_object_path (daemon, object_path);
 
8719
  if (device == data->device)
 
8720
    {
 
8721
      if (g_strcmp0 (device->priv->partition_table_scheme, data->scheme) == 0 || (device->priv->partition_table_scheme
 
8722
                                                                                  == NULL && g_strcmp0 (data->scheme, "none") == 0))
 
8723
        {
 
8724
          dbus_g_method_return (data->context);
 
8725
 
 
8726
          g_signal_handler_disconnect (daemon, data->device_changed_signal_handler_id);
 
8727
          g_source_remove (data->device_changed_timeout_id);
 
8728
          partition_table_create_data_unref (data);
 
8729
        }
 
8730
    }
 
8731
}
 
8732
 
 
8733
static gboolean
 
8734
partition_table_create_device_not_changed_cb (gpointer user_data)
 
8735
{
 
8736
  CreatePartitionTableData *data = user_data;
 
8737
 
 
8738
  throw_error (data->context, ERROR_FAILED, "Error creating partition table: timeout (10s) waiting for change");
 
8739
 
 
8740
  g_signal_handler_disconnect (data->device->priv->daemon, data->device_changed_signal_handler_id);
 
8741
  partition_table_create_data_unref (data);
 
8742
 
 
8743
  return FALSE;
 
8744
}
 
8745
 
 
8746
static void
 
8747
partition_table_create_completed_cb (DBusGMethodInvocation *context,
 
8748
                                     Device *device,
 
8749
                                     gboolean job_was_cancelled,
 
8750
                                     int status,
 
8751
                                     const char *stderr,
 
8752
                                     const char *stdout,
 
8753
                                     gpointer user_data)
 
8754
{
 
8755
  CreatePartitionTableData *data = user_data;
 
8756
 
 
8757
  /* poke the kernel so we can reread the data */
 
8758
  device_generate_kernel_change_event (device);
 
8759
 
 
8760
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
8761
    {
 
8762
 
 
8763
      if (g_strcmp0 (device->priv->partition_table_scheme, data->scheme) == 0)
 
8764
        {
 
8765
          dbus_g_method_return (context);
 
8766
        }
 
8767
      else
 
8768
        {
 
8769
          /* sit around and wait for the new partition table to appear */
 
8770
          data->device_changed_signal_handler_id
 
8771
            = g_signal_connect_after (device->priv->daemon,
 
8772
                                      "device-changed",
 
8773
                                      (GCallback) partition_table_create_device_changed_cb,
 
8774
                                      partition_table_create_data_ref (data));
 
8775
 
 
8776
          /* set up timeout for error reporting if waiting failed
 
8777
           *
 
8778
           * (the signal handler and the timeout handler share the ref to data
 
8779
           * as one will cancel the other)
 
8780
           */
 
8781
          data->device_changed_timeout_id = g_timeout_add (10 * 1000,
 
8782
                                                           partition_table_create_device_not_changed_cb,
 
8783
                                                           data);
 
8784
        }
 
8785
 
 
8786
    }
 
8787
  else
 
8788
    {
 
8789
      if (job_was_cancelled)
 
8790
        {
 
8791
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
8792
        }
 
8793
      else
 
8794
        {
 
8795
          throw_error (context,
 
8796
                       ERROR_FAILED,
 
8797
                       "Error creating partition table: helper exited with exit code %d: %s",
 
8798
                       WEXITSTATUS (status),
 
8799
                       stderr);
 
8800
        }
 
8801
    }
 
8802
}
 
8803
 
 
8804
static void
 
8805
device_partition_table_create_authorized_cb (Daemon *daemon,
 
8806
                                             Device *device,
 
8807
                                             DBusGMethodInvocation *context,
 
8808
                                             const gchar *action_id,
 
8809
                                             guint num_user_data,
 
8810
                                             gpointer *user_data_elements)
 
8811
{
 
8812
  const char *scheme = user_data_elements[0];
 
8813
  char **options = user_data_elements[1];
 
8814
  int n;
 
8815
  int m;
 
8816
  char *argv[128];
 
8817
  GError *error;
 
8818
 
 
8819
  error = NULL;
 
8820
 
 
8821
  if (device_local_is_busy (device, TRUE, TRUE, &error))
 
8822
    {
 
8823
      dbus_g_method_return_error (context, error);
 
8824
      g_error_free (error);
 
8825
      goto out;
 
8826
    }
 
8827
 
 
8828
  if (strlen (scheme) == 0)
 
8829
    {
 
8830
      throw_error (context, ERROR_FAILED, "type not specified");
 
8831
      goto out;
 
8832
    }
 
8833
 
 
8834
  n = 0;
 
8835
  argv[n++] = "udisks-helper-create-partition-table";
 
8836
  if (device->priv->device_is_linux_dmmp)
 
8837
    argv[n++] = (gchar *) get_dmmp_device_node (device);
 
8838
  else
 
8839
    argv[n++] = device->priv->device_file;
 
8840
  argv[n++] = (char *) scheme;
 
8841
  for (m = 0; options[m] != NULL; m++)
 
8842
    {
 
8843
      if (n >= (int) sizeof(argv) - 1)
 
8844
        {
 
8845
          throw_error (context, ERROR_FAILED, "Too many options");
 
8846
          goto out;
 
8847
        }
 
8848
      /* the helper will validate each option */
 
8849
      argv[n++] = (char *) options[m];
 
8850
    }
 
8851
  argv[n++] = NULL;
 
8852
 
 
8853
  if (!job_new (context,
 
8854
                "PartitionTableCreate",
 
8855
                TRUE,
 
8856
                device,
 
8857
                argv,
 
8858
                NULL,
 
8859
                partition_table_create_completed_cb,
 
8860
                FALSE,
 
8861
                partition_table_create_data_new (context, device, scheme),
 
8862
                (GDestroyNotify) partition_table_create_data_unref))
 
8863
    {
 
8864
      goto out;
 
8865
    }
 
8866
 
 
8867
 out:
 
8868
  ;
 
8869
}
 
8870
 
 
8871
gboolean
 
8872
device_partition_table_create (Device *device,
 
8873
                               const char *scheme,
 
8874
                               char **options,
 
8875
                               DBusGMethodInvocation *context)
 
8876
{
 
8877
  daemon_local_check_auth (device->priv->daemon,
 
8878
                           device,
 
8879
                           device->priv->device_is_system_internal ? "org.freedesktop.udisks.change-system-internal"
 
8880
                           : "org.freedesktop.udisks.change",
 
8881
                           "PartitionTableCreate",
 
8882
                           TRUE,
 
8883
                           device_partition_table_create_authorized_cb,
 
8884
                           context,
 
8885
                           2,
 
8886
                           g_strdup (scheme),
 
8887
                           g_free,
 
8888
                           g_strdupv (options),
 
8889
                           g_strfreev);
 
8890
  return TRUE;
 
8891
}
 
8892
 
 
8893
/*--------------------------------------------------------------------------------------------------------------*/
 
8894
 
 
8895
static Device *
 
8896
find_cleartext_device (Device *device)
 
8897
{
 
8898
  GList *devices;
 
8899
  GList *l;
 
8900
  Device *ret;
 
8901
 
 
8902
  ret = NULL;
 
8903
 
 
8904
  /* check that there isn't a cleartext device already  */
 
8905
  devices = daemon_local_get_all_devices (device->priv->daemon);
 
8906
  for (l = devices; l != NULL; l = l->next)
 
8907
    {
 
8908
      Device *d = DEVICE (l->data);
 
8909
      if (d->priv->device_is_luks_cleartext && d->priv->luks_cleartext_slave != NULL
 
8910
          && strcmp (d->priv->luks_cleartext_slave, device->priv->object_path) == 0)
 
8911
        {
 
8912
          ret = d;
 
8913
          goto out;
 
8914
        }
 
8915
    }
 
8916
 
 
8917
 out:
 
8918
 
 
8919
  g_list_free (devices);
 
8920
 
 
8921
  return ret;
 
8922
}
 
8923
 
 
8924
typedef struct
 
8925
{
 
8926
  int refcount;
 
8927
 
 
8928
  gulong device_added_signal_handler_id;
 
8929
  gulong device_changed_signal_handler_id;
 
8930
  guint device_added_timeout_id;
 
8931
 
 
8932
  DBusGMethodInvocation *context;
 
8933
  Device *device;
 
8934
 
 
8935
  UnlockEncryptionHookFunc hook_func;
 
8936
  gpointer hook_user_data;
 
8937
} UnlockEncryptionData;
 
8938
 
 
8939
static UnlockEncryptionData *
 
8940
unlock_encryption_data_new (DBusGMethodInvocation *context,
 
8941
                            Device *device,
 
8942
                            UnlockEncryptionHookFunc hook_func,
 
8943
                            gpointer hook_user_data)
 
8944
{
 
8945
  UnlockEncryptionData *data;
 
8946
 
 
8947
  data = g_new0 (UnlockEncryptionData, 1);
 
8948
  data->refcount = 1;
 
8949
 
 
8950
  data->context = context;
 
8951
  data->device = g_object_ref (device);
 
8952
  data->hook_func = hook_func;
 
8953
  data->hook_user_data = hook_user_data;
 
8954
  return data;
 
8955
}
 
8956
 
 
8957
static UnlockEncryptionData *
 
8958
unlock_encryption_data_ref (UnlockEncryptionData *data)
 
8959
{
 
8960
  data->refcount++;
 
8961
  return data;
 
8962
}
 
8963
 
 
8964
static void
 
8965
unlock_encryption_data_unref (UnlockEncryptionData *data)
 
8966
{
 
8967
  data->refcount--;
 
8968
  if (data->refcount == 0)
 
8969
    {
 
8970
      g_object_unref (data->device);
 
8971
      g_free (data);
 
8972
    }
 
8973
}
 
8974
 
 
8975
static void
 
8976
luks_unlock_device_added_cb (Daemon *daemon,
 
8977
                             const char *object_path,
 
8978
                             gpointer user_data)
 
8979
{
 
8980
  UnlockEncryptionData *data = user_data;
 
8981
  Device *device;
 
8982
 
 
8983
  /* check the device is a cleartext partition for us */
 
8984
  device = daemon_local_find_by_object_path (daemon, object_path);
 
8985
 
 
8986
  if (device != NULL && device->priv->device_is_luks_cleartext && strcmp (device->priv->luks_cleartext_slave,
 
8987
                                                                          data->device->priv->object_path) == 0)
 
8988
    {
 
8989
 
 
8990
      g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id);
 
8991
      g_signal_handler_disconnect (daemon, data->device_changed_signal_handler_id);
 
8992
      g_source_remove (data->device_added_timeout_id);
 
8993
 
 
8994
      /* update and emit a Changed() signal on the holder since the luks-holder
 
8995
       * property indicates the cleartext device
 
8996
       */
 
8997
      update_info (data->device);
 
8998
      drain_pending_changes (data->device, FALSE);
 
8999
 
 
9000
      if (data->hook_func != NULL)
 
9001
        {
 
9002
          data->hook_func (data->context, device, data->hook_user_data);
 
9003
        }
 
9004
      else
 
9005
        {
 
9006
          dbus_g_method_return (data->context, object_path);
 
9007
        }
 
9008
 
 
9009
      unlock_encryption_data_unref (data);
 
9010
    }
 
9011
}
 
9012
 
 
9013
static gboolean
 
9014
luks_unlock_device_not_seen_cb (gpointer user_data)
 
9015
{
 
9016
  UnlockEncryptionData *data = user_data;
 
9017
 
 
9018
  g_signal_handler_disconnect (data->device->priv->daemon, data->device_added_signal_handler_id);
 
9019
  g_signal_handler_disconnect (data->device->priv->daemon, data->device_changed_signal_handler_id);
 
9020
 
 
9021
  throw_error (data->context,
 
9022
               ERROR_FAILED,
 
9023
               "Error unlocking device: timeout (10s) waiting for cleartext device to show up");
 
9024
 
 
9025
  if (data->hook_func != NULL)
 
9026
    {
 
9027
      data->hook_func (data->context, NULL, data->hook_user_data);
 
9028
    }
 
9029
 
 
9030
  unlock_encryption_data_unref (data);
 
9031
  return FALSE;
 
9032
}
 
9033
 
 
9034
static void
 
9035
luks_unlock_start_waiting_for_cleartext_device (UnlockEncryptionData *data)
 
9036
{
 
9037
  Device *cleartext_device;
 
9038
 
 
9039
  cleartext_device = find_cleartext_device (data->device);
 
9040
  if (cleartext_device != NULL)
 
9041
    {
 
9042
      /* update and emit a Changed() signal on the holder since the luks-holder
 
9043
       * property indicates the cleartext device
 
9044
       */
 
9045
      update_info (data->device);
 
9046
      drain_pending_changes (data->device, FALSE);
 
9047
 
 
9048
      if (data->hook_func != NULL)
 
9049
        {
 
9050
          data->hook_func (data->context, cleartext_device, data->hook_user_data);
 
9051
        }
 
9052
      else
 
9053
        {
 
9054
          dbus_g_method_return (data->context, cleartext_device->priv->object_path);
 
9055
        }
 
9056
 
 
9057
      unlock_encryption_data_unref (data);
 
9058
    }
 
9059
  else
 
9060
    {
 
9061
      /* sit around wait for the cleartext device to appear */
 
9062
      data->device_added_signal_handler_id = g_signal_connect_after (data->device->priv->daemon,
 
9063
                                                                     "device-added",
 
9064
                                                                     (GCallback) luks_unlock_device_added_cb,
 
9065
                                                                     data);
 
9066
      data->device_changed_signal_handler_id = g_signal_connect_after (data->device->priv->daemon,
 
9067
                                                                       "device-changed",
 
9068
                                                                       (GCallback) luks_unlock_device_added_cb,
 
9069
                                                                       data);
 
9070
 
 
9071
      /* set up timeout for error reporting if waiting failed */
 
9072
      data->device_added_timeout_id = g_timeout_add (15 * 1000, luks_unlock_device_not_seen_cb, data);
 
9073
 
 
9074
      /* Note that the signal and timeout handlers share the ref to data - one will cancel the other */
 
9075
    }
 
9076
}
 
9077
 
 
9078
static void
 
9079
luks_unlock_completed_cb (DBusGMethodInvocation *context,
 
9080
                          Device *device,
 
9081
                          gboolean job_was_cancelled,
 
9082
                          int status,
 
9083
                          const char *stderr,
 
9084
                          const char *stdout,
 
9085
                          gpointer user_data)
 
9086
{
 
9087
  UnlockEncryptionData *data = user_data;
 
9088
 
 
9089
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
9090
    {
 
9091
 
 
9092
      luks_unlock_start_waiting_for_cleartext_device (unlock_encryption_data_ref (data));
 
9093
 
 
9094
    }
 
9095
  else
 
9096
    {
 
9097
      if (job_was_cancelled)
 
9098
        {
 
9099
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
9100
        }
 
9101
      else
 
9102
        {
 
9103
          throw_error (context,
 
9104
                       ERROR_FAILED,
 
9105
                       "Error unlocking device: cryptsetup exited with exit code %d: %s",
 
9106
                       WEXITSTATUS (status),
 
9107
                       stderr);
 
9108
        }
 
9109
      if (data->hook_func != NULL)
 
9110
        {
 
9111
          data->hook_func (data->context, NULL, data->hook_user_data);
 
9112
        }
 
9113
    }
 
9114
}
 
9115
 
 
9116
static gboolean
 
9117
device_luks_unlock_internal (Device *device,
 
9118
                             const char *secret,
 
9119
                             char **options,
 
9120
                             UnlockEncryptionHookFunc hook_func,
 
9121
                             gpointer hook_user_data,
 
9122
                             DBusGMethodInvocation *context)
 
9123
{
 
9124
  int n;
 
9125
  char *argv[10];
 
9126
  char *luks_name;
 
9127
  GError *error;
 
9128
  char *secret_as_stdin;
 
9129
  uid_t uid;
 
9130
 
 
9131
  luks_name = NULL;
 
9132
  secret_as_stdin = NULL;
 
9133
  error = NULL;
 
9134
 
 
9135
  daemon_local_get_uid (device->priv->daemon, &uid, context);
 
9136
 
 
9137
  if (device_local_is_busy (device, FALSE, TRUE, &error))
 
9138
    {
 
9139
      dbus_g_method_return_error (context, error);
 
9140
      g_error_free (error);
 
9141
      goto out;
 
9142
    }
 
9143
 
 
9144
  if (device->priv->id_usage == NULL || strcmp (device->priv->id_usage, "crypto") != 0)
 
9145
    {
 
9146
      throw_error (context, ERROR_FAILED, "Not a LUKS device");
 
9147
      goto out;
 
9148
    }
 
9149
 
 
9150
  if (find_cleartext_device (device) != NULL)
 
9151
    {
 
9152
      throw_error (context, ERROR_FAILED, "Cleartext device is already unlocked");
 
9153
      goto out;
 
9154
    }
 
9155
 
 
9156
  luks_name = g_strdup_printf ("udisks-luks-uuid-%s-uid%d", device->priv->id_uuid, uid);
 
9157
  secret_as_stdin = g_strdup_printf ("%s\n", secret);
 
9158
 
 
9159
  n = 0;
 
9160
  argv[n++] = "cryptsetup";
 
9161
  argv[n++] = "-T";
 
9162
  argv[n++] = "1";
 
9163
  argv[n++] = "luksOpen";
 
9164
  argv[n++] = device->priv->device_file;
 
9165
  argv[n++] = luks_name;
 
9166
  argv[n++] = NULL;
 
9167
 
 
9168
  /* yay, so it turns out /sbin/cryptsetup returns way too early; what happens is this
 
9169
   *
 
9170
   * - invoke /sbin/cryptsetup
 
9171
   *   - temporary dm node with name temporary-cryptsetup-* appears. We ignore these,
 
9172
   *     see above
 
9173
   *   - temporary dm node removed
 
9174
   * - /sbin/cryptsetup returns with success (brings us here)
 
9175
   *   - proper dm node appears
 
9176
   *     - with the name we requested, e.g. udisks-luks-uuid-%s-uid%d
 
9177
   *   - proper dm node disappears
 
9178
   *   - proper dm node reappears
 
9179
   *
 
9180
   * Obiviously /sbin/cryptsetup shouldn't return before the dm node we are
 
9181
   * looking for is really there or ready to use. But that's not how things
 
9182
   * work.
 
9183
   *
 
9184
   * This bug has been reported here:
 
9185
   *
 
9186
   *  https://bugzilla.redhat.com/show_bug.cgi?id=530721
 
9187
   *
 
9188
   * WORKAROUND: wait for the udev queue to settle before returning. Long
 
9189
   *             term fix is device-mapper/udev integration.
 
9190
   */
 
9191
  if (!job_new (context,
 
9192
                "LuksUnlock",
 
9193
                FALSE,
 
9194
                device,
 
9195
                argv,
 
9196
                secret_as_stdin,
 
9197
                luks_unlock_completed_cb,
 
9198
                TRUE, /* see note above */
 
9199
                unlock_encryption_data_new (context, device, hook_func, hook_user_data),
 
9200
                (GDestroyNotify) unlock_encryption_data_unref))
 
9201
    {
 
9202
      goto out;
 
9203
    }
 
9204
 
 
9205
 out:
 
9206
  /* scrub the secret */
 
9207
  if (secret_as_stdin != NULL)
 
9208
    {
 
9209
      memset (secret_as_stdin, '\0', strlen (secret_as_stdin));
 
9210
    }
 
9211
  g_free (secret_as_stdin);
 
9212
  g_free (luks_name);
 
9213
  return TRUE;
 
9214
}
 
9215
 
 
9216
static void
 
9217
device_luks_unlock_authorized_cb (Daemon *daemon,
 
9218
                                  Device *device,
 
9219
                                  DBusGMethodInvocation *context,
 
9220
                                  const gchar *action_id,
 
9221
                                  guint num_user_data,
 
9222
                                  gpointer *user_data_elements)
 
9223
{
 
9224
  const char *secret = user_data_elements[0];
 
9225
  char **options = user_data_elements[1];
 
9226
  device_luks_unlock_internal (device, secret, options, NULL, NULL, context);
 
9227
}
 
9228
 
 
9229
gboolean
 
9230
device_luks_unlock (Device *device,
 
9231
                    const char *secret,
 
9232
                    char **options,
 
9233
                    DBusGMethodInvocation *context)
 
9234
{
 
9235
  if (device->priv->id_usage == NULL || strcmp (device->priv->id_usage, "crypto") != 0)
 
9236
    {
 
9237
      throw_error (context, ERROR_FAILED, "Not a LUKS device");
 
9238
      goto out;
 
9239
    }
 
9240
 
 
9241
  daemon_local_check_auth (device->priv->daemon,
 
9242
                           device,
 
9243
                           "org.freedesktop.udisks.luks-unlock",
 
9244
                           "LuksUnlock",
 
9245
                           TRUE,
 
9246
                           device_luks_unlock_authorized_cb,
 
9247
                           context,
 
9248
                           2,
 
9249
                           g_strdup (secret),
 
9250
                           g_free,
 
9251
                           g_strdupv (options),
 
9252
                           g_strfreev);
 
9253
 
 
9254
 out:
 
9255
  return TRUE;
 
9256
}
 
9257
 
 
9258
/*--------------------------------------------------------------------------------------------------------------*/
 
9259
 
 
9260
typedef struct
 
9261
{
 
9262
  int refcount;
 
9263
  DBusGMethodInvocation *context;
 
9264
  Device *luks_device;
 
9265
  Device *cleartext_device;
 
9266
  guint device_removed_signal_handler_id;
 
9267
  guint device_removed_timeout_id;
 
9268
} LockEncryptionData;
 
9269
 
 
9270
static LockEncryptionData *
 
9271
lock_encryption_data_new (DBusGMethodInvocation *context,
 
9272
                          Device *luks_device,
 
9273
                          Device *cleartext_device)
 
9274
{
 
9275
  LockEncryptionData *data;
 
9276
 
 
9277
  data = g_new0 (LockEncryptionData, 1);
 
9278
  data->refcount = 1;
 
9279
 
 
9280
  data->context = context;
 
9281
  data->luks_device = g_object_ref (luks_device);
 
9282
  data->cleartext_device = g_object_ref (cleartext_device);
 
9283
  return data;
 
9284
}
 
9285
 
 
9286
static LockEncryptionData *
 
9287
lock_encryption_data_ref (LockEncryptionData *data)
 
9288
{
 
9289
  data->refcount++;
 
9290
  return data;
 
9291
}
 
9292
 
 
9293
static void
 
9294
lock_encryption_data_unref (LockEncryptionData *data)
 
9295
{
 
9296
  data->refcount--;
 
9297
  if (data->refcount == 0)
 
9298
    {
 
9299
      g_object_unref (data->luks_device);
 
9300
      g_object_unref (data->cleartext_device);
 
9301
      g_free (data);
 
9302
    }
 
9303
}
 
9304
 
 
9305
static void
 
9306
luks_lock_wait_for_cleartext_device_removed_cb (Daemon *daemon,
 
9307
                                                const char *object_path,
 
9308
                                                gpointer user_data)
 
9309
{
 
9310
  Device *device;
 
9311
  LockEncryptionData *data = user_data;
 
9312
 
 
9313
  device = daemon_local_find_by_object_path (daemon, object_path);
 
9314
  if (device == data->cleartext_device)
 
9315
    {
 
9316
 
 
9317
      job_local_end (data->luks_device);
 
9318
 
 
9319
      /* update and emit a Changed() signal on the holder since the luks-holder
 
9320
       * property indicates the cleartext device
 
9321
       */
 
9322
      update_info (data->luks_device);
 
9323
      drain_pending_changes (data->luks_device, FALSE);
 
9324
 
 
9325
      dbus_g_method_return (data->context);
 
9326
 
 
9327
      g_signal_handler_disconnect (daemon, data->device_removed_signal_handler_id);
 
9328
      g_source_remove (data->device_removed_timeout_id);
 
9329
      lock_encryption_data_unref (data);
 
9330
    }
 
9331
}
 
9332
 
 
9333
static gboolean
 
9334
luks_lock_wait_for_cleartext_device_not_seen_cb (gpointer user_data)
 
9335
{
 
9336
  LockEncryptionData *data = user_data;
 
9337
 
 
9338
  job_local_end (data->luks_device);
 
9339
 
 
9340
  throw_error (data->context,
 
9341
               ERROR_FAILED,
 
9342
               "Error locking luks device: timeout (10s) waiting for cleartext device to be removed");
 
9343
 
 
9344
  g_signal_handler_disconnect (data->cleartext_device->priv->daemon, data->device_removed_signal_handler_id);
 
9345
  lock_encryption_data_unref (data);
 
9346
  return FALSE;
 
9347
}
 
9348
 
 
9349
static void
 
9350
luks_lock_completed_cb (DBusGMethodInvocation *context,
 
9351
                        Device *device,
 
9352
                        gboolean job_was_cancelled,
 
9353
                        int status,
 
9354
                        const char *stderr,
 
9355
                        const char *stdout,
 
9356
                        gpointer user_data)
 
9357
{
 
9358
  LockEncryptionData *data = user_data;
 
9359
 
 
9360
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
9361
    {
 
9362
 
 
9363
      /* if device is already removed, just return */
 
9364
      if (data->cleartext_device->priv->removed)
 
9365
        {
 
9366
          /* update and emit a Changed() signal on the holder since the luks-holder
 
9367
           * property indicates the cleartext device
 
9368
           */
 
9369
          update_info (data->luks_device);
 
9370
          drain_pending_changes (data->luks_device, FALSE);
 
9371
 
 
9372
          dbus_g_method_return (context);
 
9373
        }
 
9374
      else
 
9375
        {
 
9376
          /* otherwise sit and wait for the device to disappear */
 
9377
 
 
9378
          data->device_removed_signal_handler_id
 
9379
            = g_signal_connect_after (device->priv->daemon,
 
9380
                                      "device-removed",
 
9381
                                      (GCallback) luks_lock_wait_for_cleartext_device_removed_cb,
 
9382
                                      lock_encryption_data_ref (data));
 
9383
 
 
9384
          /* set up timeout for error reporting if waiting failed
 
9385
           *
 
9386
           * (the signal handler and the timeout handler share the ref to data
 
9387
           * as one will cancel the other)
 
9388
           */
 
9389
          data->device_removed_timeout_id = g_timeout_add (10 * 1000,
 
9390
                                                           luks_lock_wait_for_cleartext_device_not_seen_cb,
 
9391
                                                           data);
 
9392
 
 
9393
          job_local_start (device, "LuksLock");
 
9394
        }
 
9395
    }
 
9396
  else
 
9397
    {
 
9398
      if (job_was_cancelled)
 
9399
        {
 
9400
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
9401
        }
 
9402
      else
 
9403
        {
 
9404
          throw_error (context,
 
9405
                       ERROR_FAILED,
 
9406
                       "Error locking device: cryptsetup exited with exit code %d: %s",
 
9407
                       WEXITSTATUS (status),
 
9408
                       stderr);
 
9409
        }
 
9410
    }
 
9411
}
 
9412
 
 
9413
static gboolean
 
9414
luks_get_uid_from_dm_name (const char *dm_name,
 
9415
                           uid_t *out_uid)
 
9416
{
 
9417
  int n;
 
9418
  gboolean ret;
 
9419
  uid_t uid;
 
9420
  char *endp;
 
9421
 
 
9422
  ret = FALSE;
 
9423
 
 
9424
  if (!g_str_has_prefix (dm_name, "udisks-luks-uuid"))
 
9425
    goto out;
 
9426
 
 
9427
  /* determine who unlocked the device */
 
9428
  for (n = strlen (dm_name) - 1; n >= 0; n--)
 
9429
    {
 
9430
      if (dm_name[n] == '-')
 
9431
        break;
 
9432
    }
 
9433
  if (strncmp (dm_name + n, "-uid", 4) != 0)
 
9434
    goto out;
 
9435
 
 
9436
  uid = strtol (dm_name + n + 4, &endp, 10);
 
9437
  if (endp == NULL || *endp != '\0')
 
9438
    goto out;
 
9439
 
 
9440
  if (out_uid != NULL)
 
9441
    *out_uid = uid;
 
9442
 
 
9443
  ret = TRUE;
 
9444
 out:
 
9445
  return ret;
 
9446
}
 
9447
 
 
9448
static void
 
9449
device_luks_lock_authorized_cb (Daemon *daemon,
 
9450
                                Device *device,
 
9451
                                DBusGMethodInvocation *context,
 
9452
                                const gchar *action_id,
 
9453
                                guint num_user_data,
 
9454
                                gpointer *user_data_elements)
 
9455
{
 
9456
  /* TODO: use options */
 
9457
  //char                 **options = user_data_elements[0];
 
9458
  Device *cleartext_device;
 
9459
  int n;
 
9460
  char *argv[10];
 
9461
 
 
9462
  if (device->priv->id_usage == NULL || strcmp (device->priv->id_usage, "crypto") != 0)
 
9463
    {
 
9464
      throw_error (context, ERROR_FAILED, "Not a LUKS crypto device");
 
9465
      goto out;
 
9466
    }
 
9467
 
 
9468
  cleartext_device = find_cleartext_device (device);
 
9469
  if (cleartext_device == NULL)
 
9470
    {
 
9471
      throw_error (context, ERROR_FAILED, "Cleartext device is not unlocked");
 
9472
      goto out;
 
9473
    }
 
9474
 
 
9475
  if (cleartext_device->priv->dm_name == NULL || strlen (cleartext_device->priv->dm_name) == 0)
 
9476
    {
 
9477
      throw_error (context, ERROR_FAILED, "Cannot determine device-mapper name");
 
9478
      goto out;
 
9479
    }
 
9480
 
 
9481
  n = 0;
 
9482
  argv[n++] = "cryptsetup";
 
9483
  argv[n++] = "luksClose";
 
9484
  argv[n++] = cleartext_device->priv->dm_name;
 
9485
  argv[n++] = NULL;
 
9486
 
 
9487
  if (!job_new (context,
 
9488
                "LuksLock",
 
9489
                FALSE,
 
9490
                device,
 
9491
                argv,
 
9492
                NULL,
 
9493
                luks_lock_completed_cb,
 
9494
                FALSE,
 
9495
                lock_encryption_data_new (context, device, cleartext_device),
 
9496
                (GDestroyNotify) lock_encryption_data_unref))
 
9497
    {
 
9498
      goto out;
 
9499
    }
 
9500
 
 
9501
 out:
 
9502
  ;
 
9503
}
 
9504
 
 
9505
gboolean
 
9506
device_luks_lock (Device *device,
 
9507
                  char **options,
 
9508
                  DBusGMethodInvocation *context)
 
9509
{
 
9510
  uid_t unlocked_by_uid;
 
9511
  uid_t uid;
 
9512
  Device *cleartext_device;
 
9513
  const gchar *action_id;
 
9514
 
 
9515
  daemon_local_get_uid (device->priv->daemon, &uid, context);
 
9516
 
 
9517
  if (device->priv->id_usage == NULL || strcmp (device->priv->id_usage, "crypto") != 0)
 
9518
    {
 
9519
      throw_error (context, ERROR_FAILED, "Not a LUKS crypto device");
 
9520
      goto out;
 
9521
    }
 
9522
 
 
9523
  cleartext_device = find_cleartext_device (device);
 
9524
  if (cleartext_device == NULL)
 
9525
    {
 
9526
      throw_error (context, ERROR_FAILED, "Cleartext device is not unlocked");
 
9527
      goto out;
 
9528
    }
 
9529
 
 
9530
  if (cleartext_device->priv->dm_name == NULL || strlen (cleartext_device->priv->dm_name) == 0)
 
9531
    {
 
9532
      throw_error (context, ERROR_FAILED, "Cannot determine device-mapper name");
 
9533
      goto out;
 
9534
    }
 
9535
 
 
9536
  /* see if we (e.g. udisks) set up this clear text device */
 
9537
  if (!luks_get_uid_from_dm_name (cleartext_device->priv->dm_name, &unlocked_by_uid))
 
9538
    {
 
9539
      /* nope.. so assume uid 0 set it up.. we still allow locking
 
9540
       * the device... given enough privilege
 
9541
       */
 
9542
      unlocked_by_uid = 0;
 
9543
    }
 
9544
 
 
9545
  /* require authorization if unlocked by someone else */
 
9546
  action_id = NULL;
 
9547
  if (unlocked_by_uid != uid)
 
9548
    {
 
9549
      action_id = "org.freedesktop.udisks.luks-lock-others";
 
9550
    }
 
9551
 
 
9552
  daemon_local_check_auth (device->priv->daemon,
 
9553
                           device,
 
9554
                           action_id,
 
9555
                           "LuksLock",
 
9556
                           TRUE,
 
9557
                           device_luks_lock_authorized_cb,
 
9558
                           context,
 
9559
                           1,
 
9560
                           g_strdupv (options),
 
9561
                           g_strfreev);
 
9562
 
 
9563
 out:
 
9564
  return TRUE;
 
9565
}
 
9566
 
 
9567
/*--------------------------------------------------------------------------------------------------------------*/
 
9568
 
 
9569
static void
 
9570
luks_change_passphrase_completed_cb (DBusGMethodInvocation *context,
 
9571
                                     Device *device,
 
9572
                                     gboolean job_was_cancelled,
 
9573
                                     int status,
 
9574
                                     const char *stderr,
 
9575
                                     const char *stdout,
 
9576
                                     gpointer user_data)
 
9577
{
 
9578
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
9579
    {
 
9580
      dbus_g_method_return (context);
 
9581
    }
 
9582
  else
 
9583
    {
 
9584
      if (job_was_cancelled)
 
9585
        {
 
9586
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
9587
        }
 
9588
      else if (WEXITSTATUS (status) == 3)
 
9589
        {
 
9590
          throw_error (context,
 
9591
                       ERROR_FILESYSTEM_TOOLS_MISSING,
 
9592
                       "Error changing fs label: tool not available: %s",
 
9593
                       stderr);
 
9594
        }
 
9595
      else
 
9596
        {
 
9597
          throw_error (context,
 
9598
                       ERROR_FAILED,
 
9599
                       "Error changing secret on device: helper exited with exit code %d: %s",
 
9600
                       WEXITSTATUS (status),
 
9601
                       stderr);
 
9602
        }
 
9603
    }
 
9604
}
 
9605
 
 
9606
static void
 
9607
device_luks_change_passphrase_authorized_cb (Daemon *daemon,
 
9608
                                             Device *device,
 
9609
                                             DBusGMethodInvocation *context,
 
9610
                                             const gchar *action_id,
 
9611
                                             guint num_user_data,
 
9612
                                             gpointer *user_data_elements)
 
9613
{
 
9614
  const char *old_secret = user_data_elements[0];
 
9615
  const char *new_secret = user_data_elements[1];
 
9616
  int n;
 
9617
  char *argv[10];
 
9618
  char *secrets_as_stdin;
 
9619
 
 
9620
  secrets_as_stdin = NULL;
 
9621
 
 
9622
  if (device->priv->id_usage == NULL || strcmp (device->priv->id_usage, "crypto") != 0)
 
9623
    {
 
9624
      throw_error (context, ERROR_FAILED, "Not a LUKS crypto device");
 
9625
      goto out;
 
9626
    }
 
9627
 
 
9628
  secrets_as_stdin = g_strdup_printf ("%s\n%s\n", old_secret, new_secret);
 
9629
 
 
9630
  n = 0;
 
9631
  argv[n++] = "udisks-helper-change-luks-password";
 
9632
  argv[n++] = device->priv->device_file;
 
9633
  argv[n++] = NULL;
 
9634
 
 
9635
  if (!job_new (context,
 
9636
                "LuksChangePassphrase",
 
9637
                FALSE,
 
9638
                device,
 
9639
                argv,
 
9640
                secrets_as_stdin,
 
9641
                luks_change_passphrase_completed_cb,
 
9642
                FALSE,
 
9643
                NULL,
 
9644
                NULL))
 
9645
    {
 
9646
      goto out;
 
9647
    }
 
9648
 
 
9649
 out:
 
9650
  /* scrub the secrets */
 
9651
  if (secrets_as_stdin != NULL)
 
9652
    {
 
9653
      memset (secrets_as_stdin, '\0', strlen (secrets_as_stdin));
 
9654
    }
 
9655
  g_free (secrets_as_stdin);
 
9656
}
 
9657
 
 
9658
gboolean
 
9659
device_luks_change_passphrase (Device *device,
 
9660
                               const char *old_secret,
 
9661
                               const char *new_secret,
 
9662
                               DBusGMethodInvocation *context)
 
9663
{
 
9664
  /* No need to check for busy; we can actually do this while the device is unlocked as
 
9665
   * only LUKS metadata is modified.
 
9666
   */
 
9667
 
 
9668
  if (device->priv->id_usage == NULL || strcmp (device->priv->id_usage, "crypto") != 0)
 
9669
    {
 
9670
      throw_error (context, ERROR_FAILED, "Not a LUKS crypto device");
 
9671
      goto out;
 
9672
    }
 
9673
 
 
9674
  daemon_local_check_auth (device->priv->daemon,
 
9675
                           device,
 
9676
                           device->priv->device_is_system_internal ? "org.freedesktop.udisks.change-system-internal"
 
9677
                           : "org.freedesktop.udisks.change",
 
9678
                           "LuksChangePassphrase",
 
9679
                           TRUE,
 
9680
                           device_luks_change_passphrase_authorized_cb,
 
9681
                           context,
 
9682
                           2,
 
9683
                           g_strdup (old_secret),
 
9684
                           g_free,
 
9685
                           g_strdup (new_secret),
 
9686
                           g_free);
 
9687
 
 
9688
 out:
 
9689
  return TRUE;
 
9690
}
 
9691
 
 
9692
/*--------------------------------------------------------------------------------------------------------------*/
 
9693
 
 
9694
static void
 
9695
filesystem_set_label_completed_cb (DBusGMethodInvocation *context,
 
9696
                                   Device *device,
 
9697
                                   gboolean job_was_cancelled,
 
9698
                                   int status,
 
9699
                                   const char *stderr,
 
9700
                                   const char *stdout,
 
9701
                                   gpointer user_data)
 
9702
{
 
9703
  char *new_label = user_data;
 
9704
 
 
9705
  /* poke the kernel so we can reread the data */
 
9706
  device_generate_kernel_change_event (device);
 
9707
 
 
9708
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
9709
    {
 
9710
 
 
9711
      /* update local copy, don't wait for the kernel */
 
9712
      device_set_id_label (device, new_label);
 
9713
 
 
9714
      drain_pending_changes (device, FALSE);
 
9715
 
 
9716
      dbus_g_method_return (context);
 
9717
 
 
9718
    }
 
9719
  else
 
9720
    {
 
9721
      if (job_was_cancelled)
 
9722
        {
 
9723
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
9724
        }
 
9725
      else
 
9726
        {
 
9727
          throw_error (context,
 
9728
                       ERROR_FAILED,
 
9729
                       "Error changing fslabel: helper exited with exit code %d: %s",
 
9730
                       WEXITSTATUS (status),
 
9731
                       stderr);
 
9732
        }
 
9733
    }
 
9734
}
 
9735
 
 
9736
static void
 
9737
device_filesystem_set_label_authorized_cb (Daemon *daemon,
 
9738
                                           Device *device,
 
9739
                                           DBusGMethodInvocation *context,
 
9740
                                           const gchar *action_id,
 
9741
                                           guint num_user_data,
 
9742
                                           gpointer *user_data_elements)
 
9743
{
 
9744
  const gchar *new_label = user_data_elements[0];
 
9745
  int n;
 
9746
  char *argv[10];
 
9747
  const Filesystem *fs_details;
 
9748
  GError *error;
 
9749
 
 
9750
  error = NULL;
 
9751
 
 
9752
  if (device->priv->id_usage == NULL || strcmp (device->priv->id_usage, "filesystem") != 0)
 
9753
    {
 
9754
      throw_error (context, ERROR_FAILED, "Not a mountable file system");
 
9755
      goto out;
 
9756
    }
 
9757
 
 
9758
  fs_details = daemon_local_get_fs_details (device->priv->daemon, device->priv->id_type);
 
9759
  if (fs_details == NULL)
 
9760
    {
 
9761
      throw_error (context, ERROR_BUSY, "Unknown filesystem");
 
9762
      goto out;
 
9763
    }
 
9764
 
 
9765
  if (!fs_details->supports_online_label_rename)
 
9766
    {
 
9767
      if (device_local_is_busy (device, FALSE, TRUE, &error))
 
9768
        {
 
9769
          dbus_g_method_return_error (context, error);
 
9770
          g_error_free (error);
 
9771
          goto out;
 
9772
        }
 
9773
    }
 
9774
 
 
9775
  n = 0;
 
9776
  argv[n++] = "udisks-helper-change-filesystem-label";
 
9777
  argv[n++] = device->priv->device_file;
 
9778
  argv[n++] = device->priv->id_type;
 
9779
  argv[n++] = (char *) new_label;
 
9780
  argv[n++] = NULL;
 
9781
 
 
9782
  if (!job_new (context,
 
9783
                "FilesystemSetLabel",
 
9784
                FALSE,
 
9785
                device,
 
9786
                argv,
 
9787
                NULL,
 
9788
                filesystem_set_label_completed_cb,
 
9789
                FALSE,
 
9790
                g_strdup (new_label),
 
9791
                g_free))
 
9792
    {
 
9793
      goto out;
 
9794
    }
 
9795
 
 
9796
 out:
 
9797
  ;
 
9798
}
 
9799
 
 
9800
gboolean
 
9801
device_filesystem_set_label (Device *device,
 
9802
                             const char *new_label,
 
9803
                             DBusGMethodInvocation *context)
 
9804
{
 
9805
  const Filesystem *fs_details;
 
9806
  GError *error;
 
9807
 
 
9808
  error = NULL;
 
9809
 
 
9810
  if (device->priv->id_usage == NULL || strcmp (device->priv->id_usage, "filesystem") != 0)
 
9811
    {
 
9812
      throw_error (context, ERROR_FAILED, "Not a mountable file system");
 
9813
      goto out;
 
9814
    }
 
9815
 
 
9816
  fs_details = daemon_local_get_fs_details (device->priv->daemon, device->priv->id_type);
 
9817
  if (fs_details == NULL)
 
9818
    {
 
9819
      throw_error (context, ERROR_BUSY, "Unknown filesystem");
 
9820
      goto out;
 
9821
    }
 
9822
 
 
9823
  if (!fs_details->supports_online_label_rename)
 
9824
    {
 
9825
      if (device_local_is_busy (device, FALSE, TRUE, &error))
 
9826
        {
 
9827
          dbus_g_method_return_error (context, error);
 
9828
          g_error_free (error);
 
9829
          goto out;
 
9830
        }
 
9831
    }
 
9832
 
 
9833
  daemon_local_check_auth (device->priv->daemon,
 
9834
                           device,
 
9835
                           device->priv->device_is_system_internal ? "org.freedesktop.udisks.change-system-internal"
 
9836
                           : "org.freedesktop.udisks.change",
 
9837
                           "FilesystemSetLabel",
 
9838
                           TRUE,
 
9839
                           device_filesystem_set_label_authorized_cb,
 
9840
                           context,
 
9841
                           1,
 
9842
                           g_strdup (new_label),
 
9843
                           g_free);
 
9844
 
 
9845
 out:
 
9846
  return TRUE;
 
9847
}
 
9848
 
 
9849
/*--------------------------------------------------------------------------------------------------------------*/
 
9850
 
 
9851
/* may be called with context==NULL */
 
9852
static void
 
9853
drive_ata_smart_refresh_data_completed_cb (DBusGMethodInvocation *context,
 
9854
                                           Device *device,
 
9855
                                           gboolean job_was_cancelled,
 
9856
                                           int status,
 
9857
                                           const char *stderr,
 
9858
                                           const char *stdout,
 
9859
                                           gpointer user_data)
 
9860
{
 
9861
  gint rc;
 
9862
  SkDisk *d;
 
9863
  gchar *blob;
 
9864
  gsize blob_size;
 
9865
  time_t time_collected;
 
9866
  SkSmartOverall overall;
 
9867
 
 
9868
  PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) start", device->priv->native_path);
 
9869
 
 
9870
  d = NULL;
 
9871
  blob = NULL;
 
9872
 
 
9873
  if (job_was_cancelled || stdout == NULL)
 
9874
    {
 
9875
      if (job_was_cancelled)
 
9876
        {
 
9877
          if (context != NULL)
 
9878
            throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
9879
        }
 
9880
      else
 
9881
        {
 
9882
          if (context != NULL)
 
9883
            throw_error (context,
 
9884
                         ERROR_FAILED,
 
9885
                         "Error retrieving ATA SMART data: no output",
 
9886
                         WEXITSTATUS (status),
 
9887
                         stderr);
 
9888
        }
 
9889
      goto out;
 
9890
    }
 
9891
 
 
9892
  rc = WEXITSTATUS (status);
 
9893
 
 
9894
  if (rc != 0)
 
9895
    {
 
9896
      if (rc == 2)
 
9897
        {
 
9898
          if (context != NULL)
 
9899
            {
 
9900
              throw_error (context, ERROR_ATA_SMART_WOULD_WAKEUP, "Error retrieving ATA SMART data: %s", stderr);
 
9901
            }
 
9902
        }
 
9903
      else
 
9904
        {
 
9905
          if (context != NULL)
 
9906
            {
 
9907
              throw_error (context,
 
9908
                           ERROR_FAILED,
 
9909
                           "Error retrieving ATA SMART data: helper failed with exit code %d: %s",
 
9910
                           rc,
 
9911
                           stderr);
 
9912
            }
 
9913
        }
 
9914
      goto out;
 
9915
    }
 
9916
 
 
9917
  PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) decode blob", device->priv->native_path);
 
9918
  blob = (gchar *) g_base64_decode (stdout, &blob_size);
 
9919
 
 
9920
  PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) set blob", device->priv->native_path);
 
9921
  if (blob == NULL)
 
9922
    {
 
9923
      if (context != NULL)
 
9924
        {
 
9925
          throw_error (context, ERROR_FAILED, "Error decoding ATA SMART data: invalid base64 format: %s", stdout);
 
9926
        }
 
9927
      else
 
9928
        {
 
9929
          g_warning ("Error decoding ATA SMART data: invalid base64 format: %s", stdout);
 
9930
        }
 
9931
      goto out;
 
9932
    }
 
9933
 
 
9934
  if (sk_disk_open (NULL, &d) != 0)
 
9935
    {
 
9936
      if (context != NULL)
 
9937
        {
 
9938
          throw_error (context, ERROR_FAILED, "unable to open a SkDisk");
 
9939
        }
 
9940
      goto out;
 
9941
    }
 
9942
 
 
9943
  if (sk_disk_set_blob (d, blob, blob_size) != 0)
 
9944
    {
 
9945
      if (context != NULL)
 
9946
        {
 
9947
          throw_error (context, ERROR_FAILED, "error parsing blob: %s", strerror (errno));
 
9948
        }
 
9949
      goto out;
 
9950
    }
 
9951
 
 
9952
  PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) time collected", device->priv->native_path);
 
9953
  time_collected = time (NULL);
 
9954
  device_set_drive_ata_smart_time_collected (device, time_collected);
 
9955
 
 
9956
  PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) overall smart status", device->priv->native_path);
 
9957
  if (sk_disk_smart_get_overall (d, &overall) != 0)
 
9958
    overall = -1;
 
9959
  device_set_drive_ata_smart_status (device, overall);
 
9960
  device_set_drive_ata_smart_blob_steal (device, blob, blob_size);
 
9961
  blob = NULL;
 
9962
 
 
9963
  /* emit change event since we've updated the smart data */
 
9964
  PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) drain pending changes", device->priv->native_path);
 
9965
  drain_pending_changes (device, FALSE);
 
9966
 
 
9967
  if (context != NULL)
 
9968
    dbus_g_method_return (context);
 
9969
 
 
9970
 out:
 
9971
  g_free (blob);
 
9972
  if (d != NULL)
 
9973
    sk_disk_free (d);
 
9974
  PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) end", device->priv->native_path);
 
9975
}
 
9976
 
 
9977
static void
 
9978
device_drive_ata_smart_refresh_data_authorized_cb (Daemon *daemon,
 
9979
                                                   Device *device,
 
9980
                                                   DBusGMethodInvocation *context,
 
9981
                                                   const gchar *action_id,
 
9982
                                                   guint num_user_data,
 
9983
                                                   gpointer *user_data_elements)
 
9984
{
 
9985
  char **options = user_data_elements[0];
 
9986
  int n;
 
9987
  char *argv[10];
 
9988
  const char *simuldata;
 
9989
  gboolean nowakeup;
 
9990
  uid_t caller_uid;
 
9991
 
 
9992
  PROFILE ("device_drive_ata_smart_refresh_data_authorized_cb(device=%s) start", device->priv->native_path);
 
9993
  daemon_local_get_uid (device->priv->daemon, &caller_uid, context);
 
9994
 
 
9995
  simuldata = NULL;
 
9996
  nowakeup = FALSE;
 
9997
  for (n = 0; options[n] != NULL; n++)
 
9998
    {
 
9999
      if (g_str_has_prefix (options[n], "simulate="))
 
10000
        {
 
10001
          if (context != NULL)
 
10002
            {
 
10003
              if (caller_uid != 0)
 
10004
                {
 
10005
                  throw_error (context, ERROR_FAILED, "Only uid 0 may use the simulate= option");
 
10006
                  goto out;
 
10007
                }
 
10008
            }
 
10009
          simuldata = (const char *) options[n] + 9;
 
10010
          device_set_drive_ata_smart_is_available (device, TRUE);
 
10011
        }
 
10012
      else if (strcmp (options[n], "nowakeup") == 0)
 
10013
        {
 
10014
          nowakeup = TRUE;
 
10015
        }
 
10016
    }
 
10017
 
 
10018
  if (!device->priv->drive_ata_smart_is_available)
 
10019
    {
 
10020
      throw_error (context, ERROR_FAILED, "Device does not support ATA SMART");
 
10021
      goto out;
 
10022
    }
 
10023
 
 
10024
  if (simuldata != NULL)
 
10025
    {
 
10026
      n = 0;
 
10027
      argv[n++] = "base64"; /* provided by coreutils */
 
10028
      argv[n++] = (char *) simuldata;
 
10029
      argv[n++] = NULL;
 
10030
    }
 
10031
  else
 
10032
    {
 
10033
      n = 0;
 
10034
      argv[n++] = "udisks-helper-ata-smart-collect";
 
10035
      argv[n++] = device->priv->device_file;
 
10036
      argv[n++] = nowakeup ? "1" : "0";
 
10037
      argv[n++] = NULL;
 
10038
    }
 
10039
 
 
10040
  if (!job_new (context, NULL, /* don't run this as a job */
 
10041
                FALSE, device, argv, NULL, drive_ata_smart_refresh_data_completed_cb, FALSE, NULL, NULL))
 
10042
    {
 
10043
      goto out;
 
10044
    }
 
10045
 
 
10046
 out:
 
10047
  ;
 
10048
  PROFILE ("device_drive_ata_smart_refresh_data_authorized_cb(device=%s) end", device->priv->native_path);
 
10049
}
 
10050
 
 
10051
/* may be called with context==NULL */
 
10052
gboolean
 
10053
device_drive_ata_smart_refresh_data (Device *device,
 
10054
                                     char **options,
 
10055
                                     DBusGMethodInvocation *context)
 
10056
{
 
10057
  const gchar *action_id;
 
10058
 
 
10059
  action_id = NULL;
 
10060
  if (context != NULL)
 
10061
    {
 
10062
      action_id = "org.freedesktop.udisks.drive-ata-smart-refresh";
 
10063
    }
 
10064
 
 
10065
  daemon_local_check_auth (device->priv->daemon,
 
10066
                           device,
 
10067
                           action_id,
 
10068
                           "DriveAtaSmartRefreshData",
 
10069
                           TRUE,
 
10070
                           device_drive_ata_smart_refresh_data_authorized_cb,
 
10071
                           context,
 
10072
                           1,
 
10073
                           g_strdupv (options),
 
10074
                           g_strfreev);
 
10075
 
 
10076
  return TRUE;
 
10077
}
 
10078
 
 
10079
/*--------------------------------------------------------------------------------------------------------------*/
 
10080
 
 
10081
static void
 
10082
drive_ata_smart_initiate_selftest_completed_cb (DBusGMethodInvocation *context,
 
10083
                                                Device *device,
 
10084
                                                gboolean job_was_cancelled,
 
10085
                                                int status,
 
10086
                                                const char *stderr,
 
10087
                                                const char *stdout,
 
10088
                                                gpointer user_data)
 
10089
{
 
10090
  char *options[] =
 
10091
    { NULL };
 
10092
 
 
10093
  /* no matter what happened, refresh the data */
 
10094
  device_drive_ata_smart_refresh_data (device, options, NULL);
 
10095
 
 
10096
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
10097
    {
 
10098
 
 
10099
      dbus_g_method_return (context);
 
10100
 
 
10101
    }
 
10102
  else
 
10103
    {
 
10104
      if (job_was_cancelled)
 
10105
        {
 
10106
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
10107
        }
 
10108
      else
 
10109
        {
 
10110
          throw_error (context,
 
10111
                       ERROR_FAILED,
 
10112
                       "Error running self test: helper exited with exit code %d: %s",
 
10113
                       WEXITSTATUS (status),
 
10114
                       stderr);
 
10115
        }
 
10116
    }
 
10117
}
 
10118
 
 
10119
static void
 
10120
device_drive_ata_smart_initiate_selftest_authorized_cb (Daemon *daemon,
 
10121
                                                        Device *device,
 
10122
                                                        DBusGMethodInvocation *context,
 
10123
                                                        const gchar *action_id,
 
10124
                                                        guint num_user_data,
 
10125
                                                        gpointer *user_data_elements)
 
10126
{
 
10127
  const gchar *test = user_data_elements[0];
 
10128
  /* TODO: use options */
 
10129
  //gchar       **options = user_data_elements[1];
 
10130
  int n;
 
10131
  char *argv[10];
 
10132
  const gchar *job_name;
 
10133
 
 
10134
  if (g_strcmp0 (test, "short") == 0)
 
10135
    {
 
10136
      job_name = "DriveAtaSmartSelftestShort";
 
10137
    }
 
10138
  else if (g_strcmp0 (test, "extended") == 0)
 
10139
    {
 
10140
      job_name = "DriveAtaSmartSelftestExtended";
 
10141
    }
 
10142
  else if (g_strcmp0 (test, "conveyance") == 0)
 
10143
    {
 
10144
      job_name = "DriveAtaSmartSelftestConveyance";
 
10145
    }
 
10146
  else
 
10147
    {
 
10148
      throw_error (context, ERROR_FAILED, "Malformed test");
 
10149
      goto out;
 
10150
    }
 
10151
 
 
10152
  n = 0;
 
10153
  argv[n++] = "udisks-helper-ata-smart-selftest";
 
10154
  argv[n++] = device->priv->device_file;
 
10155
  argv[n++] = (char *) test;
 
10156
  argv[n++] = NULL;
 
10157
 
 
10158
  if (!job_new (context,
 
10159
                job_name,
 
10160
                TRUE,
 
10161
                device,
 
10162
                argv,
 
10163
                NULL,
 
10164
                drive_ata_smart_initiate_selftest_completed_cb,
 
10165
                FALSE,
 
10166
                NULL,
 
10167
                NULL))
 
10168
    {
 
10169
      goto out;
 
10170
    }
 
10171
 
 
10172
 out:
 
10173
  ;
 
10174
}
 
10175
 
 
10176
gboolean
 
10177
device_drive_ata_smart_initiate_selftest (Device *device,
 
10178
                                          const char *test,
 
10179
                                          gchar **options,
 
10180
                                          DBusGMethodInvocation *context)
 
10181
{
 
10182
  if (!device->priv->drive_ata_smart_is_available)
 
10183
    {
 
10184
      throw_error (context, ERROR_FAILED, "Device does not support ATA SMART");
 
10185
      goto out;
 
10186
    }
 
10187
 
 
10188
  daemon_local_check_auth (device->priv->daemon,
 
10189
                           device,
 
10190
                           "org.freedesktop.udisks.drive-ata-smart-selftest",
 
10191
                           "DriveAtaSmartInitiateSelftest",
 
10192
                           TRUE,
 
10193
                           device_drive_ata_smart_initiate_selftest_authorized_cb,
 
10194
                           context,
 
10195
                           2,
 
10196
                           g_strdup (test),
 
10197
                           g_free,
 
10198
                           g_strdupv (options),
 
10199
                           g_strfreev);
 
10200
 
 
10201
 out:
 
10202
  return TRUE;
 
10203
}
 
10204
 
 
10205
/*--------------------------------------------------------------------------------------------------------------*/
 
10206
 
 
10207
static void
 
10208
linux_md_stop_completed_cb (DBusGMethodInvocation *context,
 
10209
                            Device *device,
 
10210
                            gboolean job_was_cancelled,
 
10211
                            int status,
 
10212
                            const char *stderr,
 
10213
                            const char *stdout,
 
10214
                            gpointer user_data)
 
10215
{
 
10216
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
10217
    {
 
10218
 
 
10219
      /* the kernel side of md currently doesn't emit a 'changed' event so
 
10220
       * generate one such that the md device can disappear from our
 
10221
       * database
 
10222
       */
 
10223
      device_generate_kernel_change_event (device);
 
10224
 
 
10225
      dbus_g_method_return (context);
 
10226
 
 
10227
    }
 
10228
  else
 
10229
    {
 
10230
      if (job_was_cancelled)
 
10231
        {
 
10232
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
10233
        }
 
10234
      else
 
10235
        {
 
10236
          throw_error (context,
 
10237
                       ERROR_FAILED,
 
10238
                       "Error stopping array: mdadm exited with exit code %d: %s",
 
10239
                       WEXITSTATUS (status),
 
10240
                       stderr);
 
10241
        }
 
10242
    }
 
10243
}
 
10244
 
 
10245
static void
 
10246
device_linux_md_stop_authorized_cb (Daemon *daemon,
 
10247
                                    Device *device,
 
10248
                                    DBusGMethodInvocation *context,
 
10249
                                    const gchar *action_id,
 
10250
                                    guint num_user_data,
 
10251
                                    gpointer *user_data_elements)
 
10252
{
 
10253
  /* TODO: use options */
 
10254
  //gchar       **options = user_data_elements[0];
 
10255
  int n;
 
10256
  char *argv[10];
 
10257
 
 
10258
  n = 0;
 
10259
  argv[n++] = "mdadm";
 
10260
  argv[n++] = "--stop";
 
10261
  argv[n++] = device->priv->device_file;
 
10262
  argv[n++] = NULL;
 
10263
 
 
10264
  if (!job_new (context, "LinuxMdStop", TRUE, device, argv, NULL, linux_md_stop_completed_cb, FALSE, NULL, NULL))
 
10265
    {
 
10266
      goto out;
 
10267
    }
 
10268
 
 
10269
 out:
 
10270
  ;
 
10271
}
 
10272
 
 
10273
gboolean
 
10274
device_linux_md_stop (Device *device,
 
10275
                      char **options,
 
10276
                      DBusGMethodInvocation *context)
 
10277
{
 
10278
  if (!device->priv->device_is_linux_md)
 
10279
    {
 
10280
      throw_error (context, ERROR_FAILED, "Device is not a Linux md drive");
 
10281
      goto out;
 
10282
    }
 
10283
 
 
10284
  daemon_local_check_auth (device->priv->daemon,
 
10285
                           device,
 
10286
                           "org.freedesktop.udisks.linux-md",
 
10287
                           "LinuxMdStop",
 
10288
                           TRUE,
 
10289
                           device_linux_md_stop_authorized_cb,
 
10290
                           context,
 
10291
                           1,
 
10292
                           g_strdupv (options),
 
10293
                           g_strfreev);
 
10294
 
 
10295
 out:
 
10296
  return TRUE;
 
10297
}
 
10298
 
 
10299
/*--------------------------------------------------------------------------------------------------------------*/
 
10300
 
 
10301
static void
 
10302
linux_md_check_completed_cb (DBusGMethodInvocation *context,
 
10303
                             Device *device,
 
10304
                             gboolean job_was_cancelled,
 
10305
                             int status,
 
10306
                             const char *stderr,
 
10307
                             const char *stdout,
 
10308
                             gpointer user_data)
 
10309
{
 
10310
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
10311
    {
 
10312
      guint64 num_errors;
 
10313
 
 
10314
      num_errors = sysfs_get_uint64 (device->priv->native_path, "md/mismatch_cnt");
 
10315
 
 
10316
      dbus_g_method_return (context, num_errors);
 
10317
    }
 
10318
  else
 
10319
    {
 
10320
      if (job_was_cancelled)
 
10321
        {
 
10322
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
10323
        }
 
10324
      else
 
10325
        {
 
10326
          throw_error (context,
 
10327
                       ERROR_FAILED,
 
10328
                       "Error checking array: helper exited with exit code %d: %s",
 
10329
                       WEXITSTATUS (status),
 
10330
                       stderr);
 
10331
        }
 
10332
    }
 
10333
}
 
10334
 
 
10335
static void
 
10336
device_linux_md_check_authorized_cb (Daemon *daemon,
 
10337
                                     Device *device,
 
10338
                                     DBusGMethodInvocation *context,
 
10339
                                     const gchar *action_id,
 
10340
                                     guint num_user_data,
 
10341
                                     gpointer *user_data_elements)
 
10342
{
 
10343
  gchar **options = user_data_elements[0];
 
10344
  int n, m;
 
10345
  char *argv[128];
 
10346
  const gchar *job_name;
 
10347
 
 
10348
  if (!device->priv->device_is_linux_md)
 
10349
    {
 
10350
      throw_error (context, ERROR_FAILED, "Device is not a Linux md drive");
 
10351
      goto out;
 
10352
    }
 
10353
 
 
10354
  if (g_strcmp0 (device->priv->linux_md_sync_action, "idle") != 0)
 
10355
    {
 
10356
      throw_error (context, ERROR_FAILED, "Array is not idle");
 
10357
      goto out;
 
10358
    }
 
10359
 
 
10360
  n = 0;
 
10361
  argv[n++] = "udisks-helper-linux-md-check";
 
10362
  argv[n++] = device->priv->device_file;
 
10363
  argv[n++] = device->priv->native_path;
 
10364
  for (m = 0; options[m] != NULL; m++)
 
10365
    {
 
10366
      if (n >= (int) sizeof(argv) - 1)
 
10367
        {
 
10368
          throw_error (context, ERROR_FAILED, "Too many options");
 
10369
          goto out;
 
10370
        }
 
10371
      /* the helper will validate each option */
 
10372
      argv[n++] = (char *) options[m];
 
10373
    }
 
10374
  argv[n++] = NULL;
 
10375
 
 
10376
  job_name = "LinuxMdCheck";
 
10377
  for (n = 0; options != NULL && options[n] != NULL; n++)
 
10378
    if (strcmp (options[n], "repair") == 0)
 
10379
      job_name = "LinuxMdRepair";
 
10380
 
 
10381
  if (!job_new (context, job_name, TRUE, device, argv, NULL, linux_md_check_completed_cb, FALSE, NULL, NULL))
 
10382
    {
 
10383
      goto out;
 
10384
    }
 
10385
 
 
10386
 out:
 
10387
  ;
 
10388
}
 
10389
 
 
10390
gboolean
 
10391
device_linux_md_check (Device *device,
 
10392
                       char **options,
 
10393
                       DBusGMethodInvocation *context)
 
10394
{
 
10395
  guint n;
 
10396
  const gchar *job_name;
 
10397
 
 
10398
  job_name = "LinuxMdCheck";
 
10399
  for (n = 0; options != NULL && options[n] != NULL; n++)
 
10400
    if (strcmp (options[n], "repair") == 0)
 
10401
      job_name = "LinuxMdRepair";
 
10402
 
 
10403
  if (!device->priv->device_is_linux_md)
 
10404
    {
 
10405
      throw_error (context, ERROR_FAILED, "Device is not a Linux md drive");
 
10406
      goto out;
 
10407
    }
 
10408
 
 
10409
  if (g_strcmp0 (device->priv->linux_md_sync_action, "idle") != 0)
 
10410
    {
 
10411
      throw_error (context, ERROR_FAILED, "Array is not idle");
 
10412
      goto out;
 
10413
    }
 
10414
 
 
10415
  daemon_local_check_auth (device->priv->daemon,
 
10416
                           device,
 
10417
                           "org.freedesktop.udisks.linux-md",
 
10418
                           job_name,
 
10419
                           TRUE,
 
10420
                           device_linux_md_check_authorized_cb,
 
10421
                           context,
 
10422
                           1,
 
10423
                           g_strdupv (options),
 
10424
                           g_strfreev);
 
10425
 
 
10426
 out:
 
10427
  return TRUE;
 
10428
}
 
10429
 
 
10430
/*--------------------------------------------------------------------------------------------------------------*/
 
10431
 
 
10432
static void
 
10433
linux_md_add_spare_completed_cb (DBusGMethodInvocation *context,
 
10434
                                     Device *device,
 
10435
                                     gboolean job_was_cancelled,
 
10436
                                     int status,
 
10437
                                     const char *stderr,
 
10438
                                     const char *stdout,
 
10439
                                     gpointer user_data)
 
10440
{
 
10441
  Device *slave = DEVICE (user_data);
 
10442
 
 
10443
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
10444
    {
 
10445
 
 
10446
      /* the slave got new metadata on it; reread that */
 
10447
      device_generate_kernel_change_event (slave);
 
10448
 
 
10449
      /* the kernel side of md currently doesn't emit a 'changed' event so
 
10450
       * generate one since state may have changed (e.g. rebuild started etc.)
 
10451
       */
 
10452
      device_generate_kernel_change_event (device);
 
10453
 
 
10454
      dbus_g_method_return (context);
 
10455
 
 
10456
    }
 
10457
  else
 
10458
    {
 
10459
      if (job_was_cancelled)
 
10460
        {
 
10461
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
10462
        }
 
10463
      else
 
10464
        {
 
10465
          throw_error (context,
 
10466
                       ERROR_FAILED,
 
10467
                       "Error adding spare: mdadm exited with exit code %d: %s",
 
10468
                       WEXITSTATUS (status),
 
10469
                       stderr);
 
10470
        }
 
10471
    }
 
10472
}
 
10473
 
 
10474
static void
 
10475
device_linux_md_add_spare_authorized_cb (Daemon *daemon,
 
10476
                                             Device *device,
 
10477
                                             DBusGMethodInvocation *context,
 
10478
                                             const gchar *action_id,
 
10479
                                             guint num_user_data,
 
10480
                                             gpointer *user_data_elements)
 
10481
{
 
10482
  char *component = user_data_elements[0];
 
10483
  /* TODO: use options */
 
10484
  //char                 **options   = user_data_elements[1];
 
10485
  int n;
 
10486
  char *argv[10];
 
10487
  GError *error;
 
10488
  Device *slave;
 
10489
 
 
10490
  error = NULL;
 
10491
 
 
10492
  slave = daemon_local_find_by_object_path (device->priv->daemon, component);
 
10493
  if (slave == NULL)
 
10494
    {
 
10495
      throw_error (context, ERROR_FAILED, "Component doesn't exist");
 
10496
      goto out;
 
10497
    }
 
10498
 
 
10499
  /* it's fine if the given device isn't a Linux md component _yet_; think
 
10500
   * hot adding a new disk if an old one failed
 
10501
   */
 
10502
 
 
10503
  if (device_local_is_busy (slave, TRUE, TRUE, &error))
 
10504
    {
 
10505
      dbus_g_method_return_error (context, error);
 
10506
      g_error_free (error);
 
10507
      goto out;
 
10508
    }
 
10509
 
 
10510
  /* TODO: check component size is OK */
 
10511
 
 
10512
  n = 0;
 
10513
  argv[n++] = "mdadm";
 
10514
  argv[n++] = "--manage";
 
10515
  argv[n++] = device->priv->device_file;
 
10516
  argv[n++] = "--add";
 
10517
  argv[n++] = slave->priv->device_file;
 
10518
  argv[n++] = "--force";
 
10519
  argv[n++] = NULL;
 
10520
 
 
10521
  if (!job_new (context,
 
10522
                "LinuxMdAddSpare",
 
10523
                TRUE,
 
10524
                device,
 
10525
                argv,
 
10526
                NULL,
 
10527
                linux_md_add_spare_completed_cb,
 
10528
                FALSE,
 
10529
                g_object_ref (slave),
 
10530
                g_object_unref))
 
10531
    {
 
10532
      goto out;
 
10533
    }
 
10534
 
 
10535
 out:
 
10536
  ;
 
10537
}
 
10538
 
 
10539
gboolean
 
10540
device_linux_md_add_spare (Device *device,
 
10541
                           char *component,
 
10542
                           char **options,
 
10543
                           DBusGMethodInvocation *context)
 
10544
{
 
10545
  if (!device->priv->device_is_linux_md)
 
10546
    {
 
10547
      throw_error (context, ERROR_FAILED, "Device is not a Linux md drive");
 
10548
      goto out;
 
10549
    }
 
10550
 
 
10551
  daemon_local_check_auth (device->priv->daemon,
 
10552
                           device,
 
10553
                           "org.freedesktop.udisks.linux-md",
 
10554
                           "LinuxMdAddSpare",
 
10555
                           TRUE,
 
10556
                           device_linux_md_add_spare_authorized_cb,
 
10557
                           context,
 
10558
                           2,
 
10559
                           g_strdup (component),
 
10560
                           g_free,
 
10561
                           g_strdupv (options),
 
10562
                           g_strfreev);
 
10563
 out:
 
10564
  return TRUE;
 
10565
}
 
10566
 
 
10567
/*--------------------------------------------------------------------------------------------------------------*/
 
10568
 
 
10569
static void
 
10570
linux_md_expand_completed_cb (DBusGMethodInvocation *context,
 
10571
                                     Device *device,
 
10572
                                     gboolean job_was_cancelled,
 
10573
                                     int status,
 
10574
                                     const char *stderr,
 
10575
                                     const char *stdout,
 
10576
                                     gpointer user_data)
 
10577
{
 
10578
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
10579
    {
 
10580
      /* the kernel side of md currently doesn't emit a 'changed' event so
 
10581
       * generate one since state may have changed (e.g. rebuild started etc.)
 
10582
       */
 
10583
      device_generate_kernel_change_event (device);
 
10584
 
 
10585
      dbus_g_method_return (context);
 
10586
 
 
10587
    }
 
10588
  else
 
10589
    {
 
10590
      if (job_was_cancelled)
 
10591
        {
 
10592
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
10593
        }
 
10594
      else
 
10595
        {
 
10596
          throw_error (context,
 
10597
                       ERROR_FAILED,
 
10598
                       "Error expanding array: helper script exited with exit code %d: %s",
 
10599
                       WEXITSTATUS (status),
 
10600
                       stderr);
 
10601
        }
 
10602
    }
 
10603
}
 
10604
 
 
10605
static void
 
10606
device_linux_md_expand_authorized_cb (Daemon *daemon,
 
10607
                                             Device *device,
 
10608
                                             DBusGMethodInvocation *context,
 
10609
                                             const gchar *action_id,
 
10610
                                             guint num_user_data,
 
10611
                                             gpointer *user_data_elements)
 
10612
{
 
10613
  gchar **components = user_data_elements[0];
 
10614
  /* TODO: use options */
 
10615
  //char                 **options   = user_data_elements[1];
 
10616
  guint n;
 
10617
  GError *error;
 
10618
  GPtrArray *args;
 
10619
  gint new_num_raid_devices;
 
10620
  gchar *backup_filename;
 
10621
  gchar *md_basename;
 
10622
 
 
10623
  error = NULL;
 
10624
 
 
10625
  args = g_ptr_array_new_with_free_func (g_free);
 
10626
  g_ptr_array_add (args, g_strdup ("udisks-helper-mdadm-expand"));
 
10627
  g_ptr_array_add (args, g_strdup (device->priv->device_file));
 
10628
 
 
10629
  new_num_raid_devices = device->priv->linux_md_num_raid_devices + g_strv_length (components);
 
10630
  g_ptr_array_add (args, g_strdup_printf ("%d", new_num_raid_devices));
 
10631
 
 
10632
  /* TODO: choose a better name and better location */
 
10633
  md_basename = g_path_get_basename (device->priv->device_file);
 
10634
  backup_filename = g_strdup_printf ("/root/udisks-mdadm-expand-backup-file-%s-at-%" G_GUINT64_FORMAT,
 
10635
                                     md_basename,
 
10636
                                     (guint64) time (NULL));
 
10637
  g_free (md_basename);
 
10638
  g_ptr_array_add (args, backup_filename);
 
10639
 
 
10640
  for (n = 0; components != NULL && components[n] != NULL; n++)
 
10641
    {
 
10642
      Device *slave;
 
10643
 
 
10644
      slave = daemon_local_find_by_object_path (device->priv->daemon, components[n]);
 
10645
      if (slave == NULL)
 
10646
        {
 
10647
          throw_error (context,
 
10648
                       ERROR_FAILED,
 
10649
                       "Component with object path %s doesn't exist",
 
10650
                       components[n]);
 
10651
          goto out;
 
10652
        }
 
10653
 
 
10654
      if (device_local_is_busy (slave, TRUE, TRUE, &error))
 
10655
        {
 
10656
          dbus_g_method_return_error (context, error);
 
10657
          g_error_free (error);
 
10658
          goto out;
 
10659
        }
 
10660
 
 
10661
      g_ptr_array_add (args, g_strdup (slave->priv->device_file));
 
10662
    }
 
10663
  g_ptr_array_add (args, NULL);
 
10664
 
 
10665
 
 
10666
  if (!job_new (context,
 
10667
                "LinuxMdExpand",
 
10668
                TRUE,
 
10669
                device,
 
10670
                (char **) args->pdata,
 
10671
                NULL,
 
10672
                linux_md_expand_completed_cb,
 
10673
                FALSE,
 
10674
                NULL,
 
10675
                NULL))
 
10676
    {
 
10677
      goto out;
 
10678
    }
 
10679
 
 
10680
 out:
 
10681
  g_ptr_array_free (args, TRUE);
 
10682
}
 
10683
 
 
10684
gboolean
 
10685
device_linux_md_expand (Device *device,
 
10686
                        GPtrArray *components,
 
10687
                        char **options,
 
10688
                        DBusGMethodInvocation *context)
 
10689
{
 
10690
  gchar **strv;
 
10691
  guint n;
 
10692
 
 
10693
  if (!device->priv->device_is_linux_md)
 
10694
    {
 
10695
      throw_error (context, ERROR_FAILED, "Device is not a Linux md drive");
 
10696
      goto out;
 
10697
    }
 
10698
 
 
10699
  strv = (gchar **) g_new0 (gchar*, components->len + 1);
 
10700
  for (n = 0; n < components->len; n++)
 
10701
    strv[n] = g_strdup (components->pdata[n]);
 
10702
 
 
10703
  daemon_local_check_auth (device->priv->daemon,
 
10704
                           device,
 
10705
                           "org.freedesktop.udisks.linux-md",
 
10706
                           "LinuxMdExpand",
 
10707
                           TRUE,
 
10708
                           device_linux_md_expand_authorized_cb,
 
10709
                           context,
 
10710
                           2,
 
10711
                           strv,
 
10712
                           g_strfreev,
 
10713
                           g_strdupv (options),
 
10714
                           g_strfreev);
 
10715
 out:
 
10716
  return TRUE;
 
10717
}
 
10718
 
 
10719
/*--------------------------------------------------------------------------------------------------------------*/
 
10720
 
 
10721
typedef struct
 
10722
{
 
10723
  int refcount;
 
10724
 
 
10725
  DBusGMethodInvocation *context;
 
10726
  Device *slave;
 
10727
  char **options;
 
10728
 
 
10729
  guint device_changed_signal_handler_id;
 
10730
  guint device_changed_timeout_id;
 
10731
 
 
10732
} RemoveComponentData;
 
10733
 
 
10734
static RemoveComponentData *
 
10735
remove_component_data_new (DBusGMethodInvocation *context,
 
10736
                           Device *slave,
 
10737
                           char **options)
 
10738
{
 
10739
  RemoveComponentData *data;
 
10740
 
 
10741
  data = g_new0 (RemoveComponentData, 1);
 
10742
  data->refcount = 1;
 
10743
 
 
10744
  data->context = context;
 
10745
  data->slave = g_object_ref (slave);
 
10746
  data->options = g_strdupv (options);
 
10747
  return data;
 
10748
}
 
10749
 
 
10750
static RemoveComponentData *
 
10751
remove_component_data_ref (RemoveComponentData *data)
 
10752
{
 
10753
  data->refcount++;
 
10754
  return data;
 
10755
}
 
10756
 
 
10757
static void
 
10758
remove_component_data_unref (RemoveComponentData *data)
 
10759
{
 
10760
  data->refcount--;
 
10761
  if (data->refcount == 0)
 
10762
    {
 
10763
      g_object_unref (data->slave);
 
10764
      g_free (data->options);
 
10765
      g_free (data);
 
10766
    }
 
10767
}
 
10768
 
 
10769
static void
 
10770
linux_md_remove_component_device_changed_cb (Daemon *daemon,
 
10771
                                             const char *object_path,
 
10772
                                             gpointer user_data)
 
10773
{
 
10774
  RemoveComponentData *data = user_data;
 
10775
  Device *device;
 
10776
  GError *error;
 
10777
 
 
10778
  error = NULL;
 
10779
 
 
10780
  device = daemon_local_find_by_object_path (daemon, object_path);
 
10781
  if (device == data->slave)
 
10782
    {
 
10783
 
 
10784
      if (device_local_is_busy (data->slave, FALSE, TRUE, &error))
 
10785
        {
 
10786
          dbus_g_method_return_error (data->context, error);
 
10787
          g_error_free (error);
 
10788
        }
 
10789
      else
 
10790
        {
 
10791
          gchar *fs_create_options[] =
 
10792
            { NULL };
 
10793
 
 
10794
          /* yay! now scrub it! */
 
10795
          device_filesystem_create (data->slave, "empty", fs_create_options, data->context);
 
10796
 
 
10797
          /* TODO: leaking data? */
 
10798
 
 
10799
          g_signal_handler_disconnect (daemon, data->device_changed_signal_handler_id);
 
10800
          g_source_remove (data->device_changed_timeout_id);
 
10801
        }
 
10802
    }
 
10803
}
 
10804
 
 
10805
static gboolean
 
10806
linux_md_remove_component_device_not_seen_cb (gpointer user_data)
 
10807
{
 
10808
  RemoveComponentData *data = user_data;
 
10809
 
 
10810
  throw_error (data->context,
 
10811
               ERROR_FAILED,
 
10812
               "Error removing component: timeout (10s) waiting for slave to stop being busy");
 
10813
 
 
10814
  g_signal_handler_disconnect (data->slave->priv->daemon, data->device_changed_signal_handler_id);
 
10815
  remove_component_data_unref (data);
 
10816
 
 
10817
  return FALSE;
 
10818
}
 
10819
 
 
10820
static void
 
10821
linux_md_remove_component_completed_cb (DBusGMethodInvocation *context,
 
10822
                                        Device *device,
 
10823
                                        gboolean job_was_cancelled,
 
10824
                                        int status,
 
10825
                                        const char *stderr,
 
10826
                                        const char *stdout,
 
10827
                                        gpointer user_data)
 
10828
{
 
10829
  RemoveComponentData *data = user_data;
 
10830
 
 
10831
  /* the slave got new metadata on it; reread that */
 
10832
  device_generate_kernel_change_event (data->slave);
 
10833
 
 
10834
  /* the kernel side of md currently doesn't emit a 'changed' event so
 
10835
   * generate one since state may have changed (e.g. rebuild started etc.)
 
10836
   */
 
10837
  device_generate_kernel_change_event (device);
 
10838
 
 
10839
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
10840
    {
 
10841
 
 
10842
      /* wait for the slave to be busy, then start erasing it */
 
10843
 
 
10844
      data->device_changed_signal_handler_id
 
10845
        = g_signal_connect_after (device->priv->daemon,
 
10846
                                  "device-changed",
 
10847
                                  (GCallback) linux_md_remove_component_device_changed_cb,
 
10848
                                  remove_component_data_ref (data));
 
10849
 
 
10850
      /* set up timeout for error reporting if waiting failed
 
10851
       *
 
10852
       * (the signal handler and the timeout handler share the ref to data
 
10853
       * as one will cancel the other)
 
10854
       */
 
10855
      data->device_changed_timeout_id = g_timeout_add (10 * 1000, linux_md_remove_component_device_not_seen_cb, data);
 
10856
 
 
10857
    }
 
10858
  else
 
10859
    {
 
10860
      if (job_was_cancelled)
 
10861
        {
 
10862
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
10863
        }
 
10864
      else
 
10865
        {
 
10866
          throw_error (context,
 
10867
                       ERROR_FAILED,
 
10868
                       "Error removing component: helper exited with exit code %d: %s",
 
10869
                       WEXITSTATUS (status),
 
10870
                       stderr);
 
10871
        }
 
10872
    }
 
10873
}
 
10874
 
 
10875
static void
 
10876
device_linux_md_remove_component_authorized_cb (Daemon *daemon,
 
10877
                                                Device *device,
 
10878
                                                DBusGMethodInvocation *context,
 
10879
                                                const gchar *action_id,
 
10880
                                                guint num_user_data,
 
10881
                                                gpointer *user_data_elements)
 
10882
{
 
10883
  char *component = user_data_elements[0];
 
10884
  char **options = user_data_elements[1];
 
10885
  int n, m;
 
10886
  char *argv[128];
 
10887
  Device *slave;
 
10888
 
 
10889
  slave = daemon_local_find_by_object_path (device->priv->daemon, component);
 
10890
  if (slave == NULL)
 
10891
    {
 
10892
      throw_error (context, ERROR_FAILED, "Component doesn't exist");
 
10893
      goto out;
 
10894
    }
 
10895
 
 
10896
  /* check that it really is a component of the md device */
 
10897
  for (n = 0; n < (int) device->priv->linux_md_slaves->len; n++)
 
10898
    {
 
10899
      if (strcmp (component, device->priv->linux_md_slaves->pdata[n]) == 0)
 
10900
        break;
 
10901
    }
 
10902
  if (n == (int) device->priv->linux_md_slaves->len)
 
10903
    {
 
10904
      throw_error (context, ERROR_FAILED, "Component isn't part of the running array");
 
10905
      goto out;
 
10906
    }
 
10907
 
 
10908
  n = 0;
 
10909
  argv[n++] = "udisks-helper-linux-md-remove-component";
 
10910
  argv[n++] = device->priv->device_file;
 
10911
  argv[n++] = slave->priv->device_file;
 
10912
  for (m = 0; options[m] != NULL; m++)
 
10913
    {
 
10914
      if (n >= (int) sizeof(argv) - 1)
 
10915
        {
 
10916
          throw_error (context, ERROR_FAILED, "Too many options");
 
10917
          goto out;
 
10918
        }
 
10919
      /* the helper will validate each option */
 
10920
      argv[n++] = (char *) options[m];
 
10921
    }
 
10922
  argv[n++] = NULL;
 
10923
 
 
10924
  if (!job_new (context,
 
10925
                "LinuxMdRemoveComponent",
 
10926
                TRUE,
 
10927
                device,
 
10928
                argv,
 
10929
                NULL,
 
10930
                linux_md_remove_component_completed_cb,
 
10931
                FALSE,
 
10932
                remove_component_data_new (context, slave, options),
 
10933
                (GDestroyNotify) remove_component_data_unref))
 
10934
    {
 
10935
      goto out;
 
10936
    }
 
10937
 
 
10938
 out:
 
10939
  ;
 
10940
}
 
10941
 
 
10942
gboolean
 
10943
device_linux_md_remove_component (Device *device,
 
10944
                                  char *component,
 
10945
                                  char **options,
 
10946
                                  DBusGMethodInvocation *context)
 
10947
{
 
10948
  if (!device->priv->device_is_linux_md)
 
10949
    {
 
10950
      throw_error (context, ERROR_FAILED, "Device is not a Linux md drive");
 
10951
      goto out;
 
10952
    }
 
10953
 
 
10954
  daemon_local_check_auth (device->priv->daemon,
 
10955
                           device,
 
10956
                           "org.freedesktop.udisks.linux-md",
 
10957
                           "LinuxMdRemoveComponent",
 
10958
                           TRUE,
 
10959
                           device_linux_md_remove_component_authorized_cb,
 
10960
                           context,
 
10961
                           2,
 
10962
                           g_strdup (component),
 
10963
                           g_free,
 
10964
                           g_strdupv (options),
 
10965
                           g_strfreev);
 
10966
 out:
 
10967
  return TRUE;
 
10968
}
 
10969
 
 
10970
/*--------------------------------------------------------------------------------------------------------------*/
 
10971
 
 
10972
typedef struct
 
10973
{
 
10974
  int refcount;
 
10975
 
 
10976
  guint device_added_signal_handler_id;
 
10977
  guint device_added_timeout_id;
 
10978
 
 
10979
  DBusGMethodInvocation *context;
 
10980
 
 
10981
  Daemon *daemon;
 
10982
  char *uuid;
 
10983
 
 
10984
} LinuxMdStartData;
 
10985
 
 
10986
static LinuxMdStartData *
 
10987
linux_md_start_data_new (DBusGMethodInvocation *context,
 
10988
                         Daemon *daemon,
 
10989
                         const char *uuid)
 
10990
{
 
10991
  LinuxMdStartData *data;
 
10992
 
 
10993
  data = g_new0 (LinuxMdStartData, 1);
 
10994
  data->refcount = 1;
 
10995
 
 
10996
  data->context = context;
 
10997
  data->daemon = g_object_ref (daemon);
 
10998
  data->uuid = g_strdup (uuid);
 
10999
  return data;
 
11000
}
 
11001
 
 
11002
static LinuxMdStartData *
 
11003
linux_md_start_data_ref (LinuxMdStartData *data)
 
11004
{
 
11005
  data->refcount++;
 
11006
  return data;
 
11007
}
 
11008
 
 
11009
static void
 
11010
linux_md_start_data_unref (LinuxMdStartData *data)
 
11011
{
 
11012
  data->refcount--;
 
11013
  if (data->refcount == 0)
 
11014
    {
 
11015
      g_object_unref (data->daemon);
 
11016
      g_free (data->uuid);
 
11017
      g_free (data);
 
11018
    }
 
11019
}
 
11020
 
 
11021
static void
 
11022
linux_md_start_device_added_cb (Daemon *daemon,
 
11023
                                const char *object_path,
 
11024
                                gpointer user_data)
 
11025
{
 
11026
  LinuxMdStartData *data = user_data;
 
11027
  Device *device;
 
11028
 
 
11029
  /* check the device is the one we're looking for */
 
11030
  device = daemon_local_find_by_object_path (daemon, object_path);
 
11031
 
 
11032
  if (device != NULL && device->priv->device_is_linux_md)
 
11033
    {
 
11034
 
 
11035
      /* TODO: actually check this properly by looking at slaves vs. components */
 
11036
 
 
11037
      /* yay! it is.. return value to the user */
 
11038
      dbus_g_method_return (data->context, object_path);
 
11039
 
 
11040
      g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id);
 
11041
      g_source_remove (data->device_added_timeout_id);
 
11042
      linux_md_start_data_unref (data);
 
11043
    }
 
11044
}
 
11045
 
 
11046
static gboolean
 
11047
linux_md_start_device_not_seen_cb (gpointer user_data)
 
11048
{
 
11049
  LinuxMdStartData *data = user_data;
 
11050
 
 
11051
  throw_error (data->context, ERROR_FAILED, "Error assembling array: timeout (10s) waiting for array to show up");
 
11052
 
 
11053
  g_signal_handler_disconnect (data->daemon, data->device_added_signal_handler_id);
 
11054
  linux_md_start_data_unref (data);
 
11055
  return FALSE;
 
11056
}
 
11057
 
 
11058
/* NOTE: This is job completion callback from a method on the daemon, not the device. */
 
11059
 
 
11060
static void
 
11061
linux_md_start_completed_cb (DBusGMethodInvocation *context,
 
11062
                             Device *device,
 
11063
                             gboolean job_was_cancelled,
 
11064
                             int status,
 
11065
                             const char *stderr,
 
11066
                             const char *stdout,
 
11067
                             gpointer user_data)
 
11068
{
 
11069
  LinuxMdStartData *data = user_data;
 
11070
 
 
11071
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
11072
    {
 
11073
      GList *l;
 
11074
      GList *devices;
 
11075
      char *objpath;
 
11076
 
 
11077
      /* see if the component appeared already */
 
11078
 
 
11079
      objpath = NULL;
 
11080
 
 
11081
      devices = daemon_local_get_all_devices (data->daemon);
 
11082
      for (l = devices; l != NULL; l = l->next)
 
11083
        {
 
11084
          Device *device = DEVICE (l->data);
 
11085
 
 
11086
          if (device->priv->device_is_linux_md)
 
11087
            {
 
11088
 
 
11089
              /* TODO: check properly */
 
11090
 
 
11091
              /* yup, return to caller */
 
11092
              objpath = device->priv->object_path;
 
11093
              break;
 
11094
            }
 
11095
        }
 
11096
 
 
11097
      g_list_free (devices);
 
11098
 
 
11099
      if (objpath != NULL)
 
11100
        {
 
11101
          dbus_g_method_return (context, objpath);
 
11102
        }
 
11103
      else
 
11104
        {
 
11105
          /* sit around and wait for the md array to appear */
 
11106
 
 
11107
          /* sit around wait for the cleartext device to appear */
 
11108
          data->device_added_signal_handler_id = g_signal_connect_after (data->daemon,
 
11109
                                                                         "device-added",
 
11110
                                                                         (GCallback) linux_md_start_device_added_cb,
 
11111
                                                                         linux_md_start_data_ref (data));
 
11112
 
 
11113
          /* set up timeout for error reporting if waiting failed
 
11114
           *
 
11115
           * (the signal handler and the timeout handler share the ref to data
 
11116
           * as one will cancel the other)
 
11117
           */
 
11118
          data->device_added_timeout_id = g_timeout_add (10 * 1000, linux_md_start_device_not_seen_cb, data);
 
11119
        }
 
11120
 
 
11121
    }
 
11122
  else
 
11123
    {
 
11124
      if (job_was_cancelled)
 
11125
        {
 
11126
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
11127
        }
 
11128
      else
 
11129
        {
 
11130
          throw_error (context,
 
11131
                       ERROR_FAILED,
 
11132
                       "Error assembling array: mdadm exited with exit code %d: %s",
 
11133
                       WEXITSTATUS (status),
 
11134
                       stderr);
 
11135
        }
 
11136
    }
 
11137
}
 
11138
 
 
11139
/* NOTE: This is a method on the daemon, not the device. */
 
11140
static void
 
11141
daemon_linux_md_start_authorized_cb (Daemon *daemon,
 
11142
                                     Device *device,
 
11143
                                     DBusGMethodInvocation *context,
 
11144
                                     const gchar *action_id,
 
11145
                                     guint num_user_data,
 
11146
                                     gpointer *user_data_elements)
 
11147
{
 
11148
  gchar **components_as_strv = user_data_elements[0];
 
11149
  /* TODO: use options */
 
11150
  //gchar **options            = user_data_elements[1];
 
11151
  int n;
 
11152
  int m;
 
11153
  char *argv[128];
 
11154
  GError *error;
 
11155
  char *uuid;
 
11156
  char *md_device_file;
 
11157
 
 
11158
  uuid = NULL;
 
11159
  md_device_file = NULL;
 
11160
  error = NULL;
 
11161
 
 
11162
  /* check that all given components exist, that they are indeed linux-md-components and
 
11163
   * that their uuid agrees
 
11164
   */
 
11165
  for (n = 0; components_as_strv[n] != NULL; n++)
 
11166
    {
 
11167
      Device *slave;
 
11168
      const char *component_objpath = components_as_strv[n];
 
11169
 
 
11170
      slave = daemon_local_find_by_object_path (daemon, component_objpath);
 
11171
      if (slave == NULL)
 
11172
        {
 
11173
          throw_error (context, ERROR_FAILED, "Component %s doesn't exist", component_objpath);
 
11174
          goto out;
 
11175
        }
 
11176
 
 
11177
      if (!slave->priv->device_is_linux_md_component)
 
11178
        {
 
11179
          throw_error (context, ERROR_FAILED, "%s is not a linux-md component", component_objpath);
 
11180
          goto out;
 
11181
        }
 
11182
 
 
11183
      if (n == 0)
 
11184
        {
 
11185
          uuid = g_strdup (slave->priv->linux_md_component_uuid);
 
11186
          if (uuid == NULL)
 
11187
            {
 
11188
              throw_error (context, ERROR_FAILED, "no uuid for one of the components");
 
11189
              goto out;
 
11190
            }
 
11191
        }
 
11192
      else
 
11193
        {
 
11194
          const char *this_uuid;
 
11195
          this_uuid = slave->priv->linux_md_component_uuid;
 
11196
 
 
11197
          if (this_uuid == NULL || strcmp (uuid, this_uuid) != 0)
 
11198
            {
 
11199
              throw_error (context, ERROR_FAILED, "uuid mismatch between given components");
 
11200
              goto out;
 
11201
            }
 
11202
        }
 
11203
 
 
11204
      if (device_local_is_busy (slave, FALSE, TRUE, &error))
 
11205
        {
 
11206
          dbus_g_method_return_error (context, error);
 
11207
          g_error_free (error);
 
11208
          goto out;
 
11209
        }
 
11210
    }
 
11211
 
 
11212
  /* find an unused md minor... Man, I wish mdadm could do this itself; this is slightly racy */
 
11213
  for (n = 0; TRUE; n++)
 
11214
    {
 
11215
      char *native_path;
 
11216
      char *array_state;
 
11217
 
 
11218
      /* TODO: move to /sys/class/block instead */
 
11219
      native_path = g_strdup_printf ("/sys/block/md%d", n);
 
11220
      if (!sysfs_file_exists (native_path, "md/array_state"))
 
11221
        {
 
11222
          /* Apparently this slot is free since there is no such file. So let's peruse it. */
 
11223
          g_free (native_path);
 
11224
          break;
 
11225
        }
 
11226
      else
 
11227
        {
 
11228
          array_state = sysfs_get_string (native_path, "md/array_state");
 
11229
          g_strstrip (array_state);
 
11230
          if (strcmp (array_state, "clear") == 0)
 
11231
            {
 
11232
              /* It's clear! Let's use it! */
 
11233
              g_free (array_state);
 
11234
              g_free (native_path);
 
11235
              break;
 
11236
            }
 
11237
          g_free (array_state);
 
11238
        }
 
11239
      g_free (native_path);
 
11240
    }
 
11241
 
 
11242
  md_device_file = g_strdup_printf ("/dev/md%d", n);
 
11243
 
 
11244
  n = 0;
 
11245
  argv[n++] = "mdadm";
 
11246
  argv[n++] = "--assemble";
 
11247
  argv[n++] = md_device_file;
 
11248
  argv[n++] = "--run";
 
11249
  for (m = 0; components_as_strv[m] != NULL; m++)
 
11250
    {
 
11251
      Device *slave;
 
11252
      const char *component_objpath = components_as_strv[m];
 
11253
 
 
11254
      slave = daemon_local_find_by_object_path (daemon, component_objpath);
 
11255
      if (slave == NULL)
 
11256
        {
 
11257
          throw_error (context, ERROR_FAILED, "Component %s doesn't exist", component_objpath);
 
11258
          goto out;
 
11259
        }
 
11260
 
 
11261
      if (n >= (int) sizeof(argv) - 1)
 
11262
        {
 
11263
          throw_error (context, ERROR_FAILED, "Too many components");
 
11264
          goto out;
 
11265
        }
 
11266
 
 
11267
      argv[n++] = (char *) slave->priv->device_file;
 
11268
    }
 
11269
  argv[n++] = NULL;
 
11270
 
 
11271
  if (!job_new (context,
 
11272
                "LinuxMdStart",
 
11273
                TRUE,
 
11274
                NULL,
 
11275
                argv,
 
11276
                NULL,
 
11277
                linux_md_start_completed_cb,
 
11278
                FALSE,
 
11279
                linux_md_start_data_new (context, daemon, uuid),
 
11280
                (GDestroyNotify) linux_md_start_data_unref))
 
11281
    {
 
11282
      goto out;
 
11283
    }
 
11284
 
 
11285
 out:
 
11286
  g_free (uuid);
 
11287
  g_free (md_device_file);
 
11288
}
 
11289
 
 
11290
/* NOTE: This is a method on the daemon, not the device. */
 
11291
gboolean
 
11292
daemon_linux_md_start (Daemon *daemon,
 
11293
                       GPtrArray *components,
 
11294
                       char **options,
 
11295
                       DBusGMethodInvocation *context)
 
11296
{
 
11297
  gchar **components_as_strv;
 
11298
  guint n;
 
11299
 
 
11300
  components_as_strv = g_new0 (gchar *, components->len + 1);
 
11301
  for (n = 0; n < components->len; n++)
 
11302
    components_as_strv[n] = g_strdup (components->pdata[n]);
 
11303
 
 
11304
  daemon_local_check_auth (daemon,
 
11305
                           NULL,
 
11306
                           "org.freedesktop.udisks.linux-md",
 
11307
                           "LinuxMdStart",
 
11308
                           TRUE,
 
11309
                           daemon_linux_md_start_authorized_cb,
 
11310
                           context,
 
11311
                           2,
 
11312
                           components_as_strv,
 
11313
                           g_strfreev,
 
11314
                           g_strdupv (options),
 
11315
                           g_strfreev);
 
11316
 
 
11317
  return TRUE;
 
11318
}
 
11319
 
 
11320
/*--------------------------------------------------------------------------------------------------------------*/
 
11321
 
 
11322
typedef struct
 
11323
{
 
11324
  int refcount;
 
11325
 
 
11326
  guint device_added_signal_handler_id;
 
11327
  guint device_added_timeout_id;
 
11328
 
 
11329
  DBusGMethodInvocation *context;
 
11330
 
 
11331
  Daemon *daemon;
 
11332
  char *first_component_objpath;
 
11333
 
 
11334
} LinuxMdCreateData;
 
11335
 
 
11336
static LinuxMdCreateData *
 
11337
linux_md_create_data_new (DBusGMethodInvocation *context,
 
11338
                          Daemon *daemon,
 
11339
                          const char *first_component_objpath)
 
11340
{
 
11341
  LinuxMdCreateData *data;
 
11342
 
 
11343
  data = g_new0 (LinuxMdCreateData, 1);
 
11344
  data->refcount = 1;
 
11345
 
 
11346
  data->context = context;
 
11347
  data->daemon = g_object_ref (daemon);
 
11348
  data->first_component_objpath = g_strdup (first_component_objpath);
 
11349
  return data;
 
11350
}
 
11351
 
 
11352
static LinuxMdCreateData *
 
11353
linux_md_create_data_ref (LinuxMdCreateData *data)
 
11354
{
 
11355
  data->refcount++;
 
11356
  return data;
 
11357
}
 
11358
 
 
11359
static void
 
11360
linux_md_create_data_unref (LinuxMdCreateData *data)
 
11361
{
 
11362
  data->refcount--;
 
11363
  if (data->refcount == 0)
 
11364
    {
 
11365
      g_object_unref (data->daemon);
 
11366
      g_free (data->first_component_objpath);
 
11367
      g_free (data);
 
11368
    }
 
11369
}
 
11370
 
 
11371
static void
 
11372
linux_md_create_device_added_cb (Daemon *daemon,
 
11373
                                 const char *object_path,
 
11374
                                 gpointer user_data)
 
11375
{
 
11376
  LinuxMdCreateData *data = user_data;
 
11377
  Device *device;
 
11378
 
 
11379
  /* check the device is the one we're looking for */
 
11380
  device = daemon_local_find_by_object_path (daemon, object_path);
 
11381
 
 
11382
  if (device != NULL && device->priv->device_is_linux_md)
 
11383
    {
 
11384
 
 
11385
      /* TODO: actually check this properly by looking at slaves vs. components */
 
11386
 
 
11387
      /* yay! it is.. return value to the user */
 
11388
      dbus_g_method_return (data->context, object_path);
 
11389
 
 
11390
      g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id);
 
11391
      g_source_remove (data->device_added_timeout_id);
 
11392
      linux_md_create_data_unref (data);
 
11393
    }
 
11394
}
 
11395
 
 
11396
static gboolean
 
11397
linux_md_create_device_not_seen_cb (gpointer user_data)
 
11398
{
 
11399
  LinuxMdCreateData *data = user_data;
 
11400
 
 
11401
  throw_error (data->context, ERROR_FAILED, "Error assembling array: timeout (10s) waiting for array to show up");
 
11402
 
 
11403
  g_signal_handler_disconnect (data->daemon, data->device_added_signal_handler_id);
 
11404
  linux_md_create_data_unref (data);
 
11405
  return FALSE;
 
11406
}
 
11407
 
 
11408
/* NOTE: This is job completion callback from a method on the daemon, not the device. */
 
11409
 
 
11410
static void
 
11411
linux_md_create_completed_cb (DBusGMethodInvocation *context,
 
11412
                              Device *device,
 
11413
                              gboolean job_was_cancelled,
 
11414
                              int status,
 
11415
                              const char *stderr,
 
11416
                              const char *stdout,
 
11417
                              gpointer user_data)
 
11418
{
 
11419
  LinuxMdCreateData *data = user_data;
 
11420
 
 
11421
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
11422
    {
 
11423
      GList *l;
 
11424
      GList *devices;
 
11425
      char *objpath;
 
11426
 
 
11427
      /* see if the component appeared already */
 
11428
 
 
11429
      objpath = NULL;
 
11430
 
 
11431
      devices = daemon_local_get_all_devices (data->daemon);
 
11432
      for (l = devices; l != NULL; l = l->next)
 
11433
        {
 
11434
          Device *device = DEVICE (l->data);
 
11435
 
 
11436
          if (device->priv->device_is_linux_md)
 
11437
            {
 
11438
 
 
11439
              /* TODO: check properly */
 
11440
 
 
11441
              /* yup, return to caller */
 
11442
              objpath = device->priv->object_path;
 
11443
              break;
 
11444
            }
 
11445
        }
 
11446
 
 
11447
      g_list_free (devices);
 
11448
 
 
11449
      if (objpath != NULL)
 
11450
        {
 
11451
          dbus_g_method_return (context, objpath);
 
11452
        }
 
11453
      else
 
11454
        {
 
11455
          /* sit around and wait for the md array to appear */
 
11456
 
 
11457
          /* sit around wait for the cleartext device to appear */
 
11458
          data->device_added_signal_handler_id = g_signal_connect_after (data->daemon,
 
11459
                                                                         "device-added",
 
11460
                                                                         (GCallback) linux_md_create_device_added_cb,
 
11461
                                                                         linux_md_create_data_ref (data));
 
11462
 
 
11463
          /* set up timeout for error reporting if waiting failed
 
11464
           *
 
11465
           * (the signal handler and the timeout handler share the ref to data
 
11466
           * as one will cancel the other)
 
11467
           */
 
11468
          data->device_added_timeout_id = g_timeout_add (10 * 1000, linux_md_create_device_not_seen_cb, data);
 
11469
        }
 
11470
 
 
11471
    }
 
11472
  else
 
11473
    {
 
11474
      if (job_was_cancelled)
 
11475
        {
 
11476
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
11477
        }
 
11478
      else
 
11479
        {
 
11480
          throw_error (context,
 
11481
                       ERROR_FAILED,
 
11482
                       "Error assembling array: mdadm exited with exit code %d: %s",
 
11483
                       WEXITSTATUS (status),
 
11484
                       stderr);
 
11485
        }
 
11486
    }
 
11487
}
 
11488
 
 
11489
/* NOTE: This is a method on the daemon, not the device. */
 
11490
static void
 
11491
daemon_linux_md_create_authorized_cb (Daemon *daemon,
 
11492
                                      Device *device,
 
11493
                                      DBusGMethodInvocation *context,
 
11494
                                      const gchar *action_id,
 
11495
                                      guint num_user_data,
 
11496
                                      gpointer *user_data_elements)
 
11497
{
 
11498
  gchar **components_as_strv = user_data_elements[0];
 
11499
  gchar *level = user_data_elements[1];
 
11500
  guint64 stripe_size = *((guint64*) user_data_elements[2]);
 
11501
  gchar *name = user_data_elements[3];
 
11502
  /* TODO: use options */
 
11503
  //gchar **options            = user_data_elements[4];
 
11504
  int n;
 
11505
  int m;
 
11506
  char *argv[128];
 
11507
  GError *error;
 
11508
  gchar *md_device_file;
 
11509
  gchar *num_raid_devices_as_str;
 
11510
  gchar *stripe_size_as_str;
 
11511
  gboolean use_bitmap;
 
11512
  gboolean use_chunk;
 
11513
 
 
11514
  md_device_file = NULL;
 
11515
  num_raid_devices_as_str = NULL;
 
11516
  stripe_size_as_str = NULL;
 
11517
  error = NULL;
 
11518
 
 
11519
  /* sanity-check level */
 
11520
  use_bitmap = FALSE;
 
11521
  use_chunk = FALSE;
 
11522
  if (g_strcmp0 (level, "raid0") == 0)
 
11523
    {
 
11524
      use_chunk = TRUE;
 
11525
    }
 
11526
  else if (g_strcmp0 (level, "raid1") == 0)
 
11527
    {
 
11528
      if (stripe_size > 0)
 
11529
        {
 
11530
          throw_error (context, ERROR_FAILED, "Stripe size doesn't make sense for RAID-1");
 
11531
          goto out;
 
11532
        }
 
11533
    }
 
11534
  else if (g_strcmp0 (level, "raid4") == 0 || g_strcmp0 (level, "raid5") == 0 || g_strcmp0 (level, "raid6") == 0
 
11535
           || g_strcmp0 (level, "raid10") == 0)
 
11536
    {
 
11537
      use_bitmap = TRUE;
 
11538
      use_chunk = TRUE;
 
11539
    }
 
11540
  else
 
11541
    {
 
11542
      throw_error (context, ERROR_FAILED, "Invalid level `%s'", level);
 
11543
      goto out;
 
11544
    }
 
11545
 
 
11546
  /* check that all given components exist and that they are not busy
 
11547
   */
 
11548
  for (n = 0; components_as_strv[n] != NULL; n++)
 
11549
    {
 
11550
      Device *slave;
 
11551
      const char *component_objpath = components_as_strv[n];
 
11552
 
 
11553
      slave = daemon_local_find_by_object_path (daemon, component_objpath);
 
11554
      if (slave == NULL)
 
11555
        {
 
11556
          throw_error (context, ERROR_FAILED, "Component %s doesn't exist", component_objpath);
 
11557
          goto out;
 
11558
        }
 
11559
 
 
11560
      if (device_local_is_busy (slave, FALSE, TRUE, &error))
 
11561
        {
 
11562
          dbus_g_method_return_error (context, error);
 
11563
          g_error_free (error);
 
11564
          goto out;
 
11565
        }
 
11566
    }
 
11567
 
 
11568
  /* find an unused md minor... Man, I wish mdadm could do this itself; this is slightly racy */
 
11569
  for (n = 0; TRUE; n++)
 
11570
    {
 
11571
      char *native_path;
 
11572
      char *array_state;
 
11573
 
 
11574
      /* TODO: move to /sys/class/block instead */
 
11575
      native_path = g_strdup_printf ("/sys/block/md%d", n);
 
11576
      if (!sysfs_file_exists (native_path, "md/array_state"))
 
11577
        {
 
11578
          /* Apparently this slot is free since there is no such file. So let's peruse it. */
 
11579
          g_free (native_path);
 
11580
          break;
 
11581
        }
 
11582
      else
 
11583
        {
 
11584
          array_state = sysfs_get_string (native_path, "md/array_state");
 
11585
          g_strstrip (array_state);
 
11586
          if (strcmp (array_state, "clear") == 0)
 
11587
            {
 
11588
              /* It's clear! Let's use it! */
 
11589
              g_free (array_state);
 
11590
              g_free (native_path);
 
11591
              break;
 
11592
            }
 
11593
          g_free (array_state);
 
11594
        }
 
11595
      g_free (native_path);
 
11596
    }
 
11597
 
 
11598
  md_device_file = g_strdup_printf ("/dev/md%d", n);
 
11599
 
 
11600
  num_raid_devices_as_str = g_strdup_printf ("%d", g_strv_length (components_as_strv));
 
11601
 
 
11602
  if (stripe_size > 0)
 
11603
    stripe_size_as_str = g_strdup_printf ("%d", ((gint) stripe_size) / 1024);
 
11604
 
 
11605
  n = 0;
 
11606
  argv[n++] = "mdadm";
 
11607
  argv[n++] = "--create";
 
11608
  argv[n++] = md_device_file;
 
11609
  argv[n++] = "--level";
 
11610
  argv[n++] = level;
 
11611
  argv[n++] = "--raid-devices";
 
11612
  argv[n++] = num_raid_devices_as_str;
 
11613
  argv[n++] = "--metadata";
 
11614
  argv[n++] = "1.2";
 
11615
  argv[n++] = "--name";
 
11616
  argv[n++] = name;
 
11617
  argv[n++] = "--homehost";
 
11618
  argv[n++] = "";
 
11619
  if (use_bitmap)
 
11620
    {
 
11621
      argv[n++] = "--bitmap";
 
11622
      argv[n++] = "internal";
 
11623
    }
 
11624
  if (use_chunk && stripe_size_as_str != NULL)
 
11625
    {
 
11626
      argv[n++] = "--chunk";
 
11627
      argv[n++] = stripe_size_as_str;
 
11628
    }
 
11629
  for (m = 0; components_as_strv[m] != NULL; m++)
 
11630
    {
 
11631
      Device *slave;
 
11632
      const char *component_objpath = components_as_strv[m];
 
11633
 
 
11634
      slave = daemon_local_find_by_object_path (daemon, component_objpath);
 
11635
      if (slave == NULL)
 
11636
        {
 
11637
          throw_error (context, ERROR_FAILED, "Component %s doesn't exist", component_objpath);
 
11638
          goto out;
 
11639
        }
 
11640
 
 
11641
      if (n >= (int) sizeof(argv) - 1)
 
11642
        {
 
11643
          throw_error (context, ERROR_FAILED, "Too many components");
 
11644
          goto out;
 
11645
        }
 
11646
 
 
11647
      argv[n++] = (char *) slave->priv->device_file;
 
11648
    }
 
11649
  argv[n++] = NULL;
 
11650
 
 
11651
  //for (m = 0; argv[m] != NULL; m++)
 
11652
  //        g_debug ("arg[%d] = `%s'", m, argv[m]);
 
11653
 
 
11654
  if (!job_new (context,
 
11655
                "LinuxMdCreate",
 
11656
                TRUE,
 
11657
                NULL,
 
11658
                argv,
 
11659
                NULL,
 
11660
                linux_md_create_completed_cb,
 
11661
                FALSE,
 
11662
                linux_md_create_data_new (context, daemon, components_as_strv[0]),
 
11663
                (GDestroyNotify) linux_md_create_data_unref))
 
11664
    {
 
11665
      goto out;
 
11666
    }
 
11667
 
 
11668
 out:
 
11669
  g_free (md_device_file);
 
11670
  g_free (num_raid_devices_as_str);
 
11671
  g_free (stripe_size_as_str);
 
11672
}
 
11673
 
 
11674
/* NOTE: This is a method on the daemon, not the device. */
 
11675
gboolean
 
11676
daemon_linux_md_create (Daemon *daemon,
 
11677
                        GPtrArray *components,
 
11678
                        char *level,
 
11679
                        guint64 stripe_size,
 
11680
                        char *name,
 
11681
                        char **options,
 
11682
                        DBusGMethodInvocation *context)
 
11683
{
 
11684
  gchar **components_as_strv;
 
11685
  guint n;
 
11686
 
 
11687
  components_as_strv = g_new0 (gchar *, components->len + 1);
 
11688
  for (n = 0; n < components->len; n++)
 
11689
    components_as_strv[n] = g_strdup (components->pdata[n]);
 
11690
 
 
11691
  daemon_local_check_auth (daemon,
 
11692
                           NULL,
 
11693
                           "org.freedesktop.udisks.linux-md",
 
11694
                           "LinuxMdCreate",
 
11695
                           TRUE,
 
11696
                           daemon_linux_md_create_authorized_cb,
 
11697
                           context,
 
11698
                           4,
 
11699
                           components_as_strv,
 
11700
                           g_strfreev,
 
11701
                           g_strdup (level),
 
11702
                           g_free,
 
11703
                           g_memdup (&stripe_size, sizeof(guint64)),
 
11704
                           g_free,
 
11705
                           g_strdup (name),
 
11706
                           g_free,
 
11707
                           g_strdupv (options),
 
11708
                           g_strfreev);
 
11709
 
 
11710
  return TRUE;
 
11711
}
 
11712
 
 
11713
/*--------------------------------------------------------------------------------------------------------------*/
 
11714
 
 
11715
typedef struct
 
11716
{
 
11717
  char *mount_path;
 
11718
  ForceRemovalCompleteFunc fr_callback;
 
11719
  gpointer fr_user_data;
 
11720
} ForceUnmountData;
 
11721
 
 
11722
static ForceUnmountData *
 
11723
force_unmount_data_new (const gchar *mount_path,
 
11724
                        ForceRemovalCompleteFunc fr_callback,
 
11725
                        gpointer fr_user_data)
 
11726
{
 
11727
  ForceUnmountData *data;
 
11728
 
 
11729
  data = g_new0 (ForceUnmountData, 1);
 
11730
  data->mount_path = g_strdup (mount_path);
 
11731
  data->fr_callback = fr_callback;
 
11732
  data->fr_user_data = fr_user_data;
 
11733
 
 
11734
  return data;
 
11735
}
 
11736
 
 
11737
static void
 
11738
force_unmount_data_unref (ForceUnmountData *data)
 
11739
{
 
11740
  g_free (data->mount_path);
 
11741
  g_free (data);
 
11742
}
 
11743
 
 
11744
static void
 
11745
force_unmount_completed_cb (DBusGMethodInvocation *context,
 
11746
                            Device *device,
 
11747
                            gboolean job_was_cancelled,
 
11748
                            int status,
 
11749
                            const char *stderr,
 
11750
                            const char *stdout,
 
11751
                            gpointer user_data)
 
11752
{
 
11753
  ForceUnmountData *data = user_data;
 
11754
 
 
11755
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
11756
    {
 
11757
 
 
11758
      g_print ("**** NOTE: Successfully force unmounted device %s\n", device->priv->device_file);
 
11759
      /* update_info_mount_state() will update the mounts file and clean up the directory if needed */
 
11760
      update_info (device);
 
11761
 
 
11762
      if (data->fr_callback != NULL)
 
11763
        data->fr_callback (device, TRUE, data->fr_user_data);
 
11764
    }
 
11765
  else
 
11766
    {
 
11767
      g_print ("**** NOTE: force unmount failed: %s\n", stderr);
 
11768
      if (data->fr_callback != NULL)
 
11769
        data->fr_callback (device, FALSE, data->fr_user_data);
 
11770
    }
 
11771
}
 
11772
 
 
11773
static void
 
11774
force_unmount (Device *device,
 
11775
               ForceRemovalCompleteFunc callback,
 
11776
               gpointer user_data)
 
11777
{
 
11778
  int n;
 
11779
  char *argv[16];
 
11780
  const gchar *mount_path;
 
11781
 
 
11782
  mount_path = ((gchar **) device->priv->device_mount_paths->pdata)[0];
 
11783
 
 
11784
  n = 0;
 
11785
  argv[n++] = "umount";
 
11786
  /* on Linux, we only have lazy unmount for now */
 
11787
  argv[n++] = "-l";
 
11788
  argv[n++] = (gchar *) mount_path;
 
11789
  argv[n++] = NULL;
 
11790
 
 
11791
  if (!job_new (NULL,
 
11792
                "ForceUnmount",
 
11793
                FALSE,
 
11794
                device,
 
11795
                argv,
 
11796
                NULL,
 
11797
                force_unmount_completed_cb,
 
11798
                FALSE,
 
11799
                force_unmount_data_new (mount_path, callback, user_data),
 
11800
                (GDestroyNotify) force_unmount_data_unref))
 
11801
    {
 
11802
      g_warning ("Couldn't spawn unmount for force unmounting %s", mount_path);
 
11803
      if (callback != NULL)
 
11804
        callback (device, FALSE, user_data);
 
11805
    }
 
11806
}
 
11807
 
 
11808
/*--------------------------------------------------------------------------------------------------------------*/
 
11809
 
 
11810
typedef struct
 
11811
{
 
11812
  Device *device;
 
11813
  char *dm_name;
 
11814
  ForceRemovalCompleteFunc fr_callback;
 
11815
  gpointer fr_user_data;
 
11816
} ForceLuksTeardownData;
 
11817
 
 
11818
static void
 
11819
force_luks_teardown_completed_cb (DBusGMethodInvocation *context,
 
11820
                                  Device *device,
 
11821
                                  gboolean job_was_cancelled,
 
11822
                                  int status,
 
11823
                                  const char *stderr,
 
11824
                                  const char *stdout,
 
11825
                                  gpointer user_data)
 
11826
{
 
11827
  ForceLuksTeardownData *data = user_data;
 
11828
 
 
11829
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
11830
    {
 
11831
 
 
11832
      g_print ("**** NOTE: Successfully teared down luks device %s\n", device->priv->device_file);
 
11833
 
 
11834
      if (data->fr_callback != NULL)
 
11835
        data->fr_callback (device, TRUE, data->fr_user_data);
 
11836
    }
 
11837
  else
 
11838
    {
 
11839
      g_print ("**** NOTE: force luks teardown failed: %s\n", stderr);
 
11840
      if (data->fr_callback != NULL)
 
11841
        data->fr_callback (device, FALSE, data->fr_user_data);
 
11842
    }
 
11843
}
 
11844
 
 
11845
static ForceLuksTeardownData *
 
11846
force_luks_teardown_data_new (Device *device,
 
11847
                              const char *dm_name,
 
11848
                              ForceRemovalCompleteFunc fr_callback,
 
11849
                              gpointer fr_user_data)
 
11850
{
 
11851
  ForceLuksTeardownData *data;
 
11852
 
 
11853
  data = g_new0 (ForceLuksTeardownData, 1);
 
11854
  data->device = g_object_ref (device);
 
11855
  data->dm_name = g_strdup (dm_name);
 
11856
  data->fr_callback = fr_callback;
 
11857
  data->fr_user_data = fr_user_data;
 
11858
  return data;
 
11859
}
 
11860
 
 
11861
static void
 
11862
force_luks_teardown_data_unref (ForceLuksTeardownData *data)
 
11863
{
 
11864
  if (data->device != NULL)
 
11865
    g_object_unref (data->device);
 
11866
  g_free (data->dm_name);
 
11867
  g_free (data);
 
11868
}
 
11869
 
 
11870
static void
 
11871
force_luks_teardown_cleartext_done (Device *device,
 
11872
                                    gboolean success,
 
11873
                                    gpointer user_data)
 
11874
{
 
11875
  int n;
 
11876
  char *argv[16];
 
11877
  ForceLuksTeardownData *data = user_data;
 
11878
 
 
11879
  if (!success)
 
11880
    {
 
11881
      if (data->fr_callback != NULL)
 
11882
        data->fr_callback (data->device, FALSE, data->fr_user_data);
 
11883
 
 
11884
      force_luks_teardown_data_unref (data);
 
11885
      goto out;
 
11886
    }
 
11887
 
 
11888
  /* ok, clear text device is out of the way; now tear it down */
 
11889
 
 
11890
  n = 0;
 
11891
  argv[n++] = "cryptsetup";
 
11892
  argv[n++] = "luksClose";
 
11893
  argv[n++] = data->dm_name;
 
11894
  argv[n++] = NULL;
 
11895
 
 
11896
  //g_debug ("doing cryptsetup luksClose %s", data->dm_name);
 
11897
 
 
11898
  if (!job_new (NULL,
 
11899
                "ForceLuksTeardown",
 
11900
                FALSE,
 
11901
                data->device,
 
11902
                argv,
 
11903
                NULL,
 
11904
                force_luks_teardown_completed_cb,
 
11905
                FALSE,
 
11906
                data,
 
11907
                (GDestroyNotify) force_luks_teardown_data_unref))
 
11908
    {
 
11909
 
 
11910
      g_warning ("Couldn't spawn cryptsetup for force teardown for device %s", data->dm_name);
 
11911
      if (data->fr_callback != NULL)
 
11912
        data->fr_callback (data->device, FALSE, data->fr_user_data);
 
11913
 
 
11914
      force_luks_teardown_data_unref (data);
 
11915
    }
 
11916
 out:
 
11917
  ;
 
11918
}
 
11919
 
 
11920
static void
 
11921
force_luks_teardown (Device *device,
 
11922
                     Device *cleartext_device,
 
11923
                     ForceRemovalCompleteFunc callback,
 
11924
                     gpointer user_data)
 
11925
{
 
11926
  /* first we gotta force remove the clear text device */
 
11927
  force_removal (cleartext_device,
 
11928
                 force_luks_teardown_cleartext_done,
 
11929
                 force_luks_teardown_data_new (device, cleartext_device->priv->dm_name, callback, user_data));
 
11930
}
 
11931
 
 
11932
/*--------------------------------------------------------------------------------------------------------------*/
 
11933
 
 
11934
static void
 
11935
force_removal (Device *device,
 
11936
               ForceRemovalCompleteFunc callback,
 
11937
               gpointer user_data)
 
11938
{
 
11939
  //g_debug ("in force removal for %s", device->priv->device_file);
 
11940
 
 
11941
  /* Device is going bye bye. If this device is
 
11942
   *
 
11943
   *  - Mounted by us, then forcibly unmount it.
 
11944
   *
 
11945
   *  - If it's a luks device, check if there's cleartext
 
11946
   *    companion. If so, tear it down if it was setup by us.
 
11947
   *
 
11948
   */
 
11949
  if (device->priv->device_is_mounted && device->priv->device_mount_paths->len > 0)
 
11950
    {
 
11951
      gboolean remove_dir_on_unmount;
 
11952
 
 
11953
      if (mount_file_has_device (device->priv->device_file, NULL, &remove_dir_on_unmount) ||
 
11954
          is_device_in_fstab (device, NULL))
 
11955
        {
 
11956
          g_print ("**** NOTE: Force unmounting device %s\n", device->priv->device_file);
 
11957
          force_unmount (device, callback, user_data);
 
11958
          goto pending;
 
11959
        }
 
11960
    }
 
11961
 
 
11962
  if (device->priv->id_usage != NULL && device->priv->luks_holder != NULL && strcmp (device->priv->id_usage, "crypto") == 0)
 
11963
    {
 
11964
      Device *d;
 
11965
 
 
11966
      /* look for cleartext device  */
 
11967
      d = daemon_local_find_by_object_path (device->priv->daemon, device->priv->luks_holder);
 
11968
      if (strcmp (d->priv->object_path, device->priv->luks_holder) == 0)
 
11969
        {
 
11970
          /* Check whether it is set up by us */
 
11971
          if (d->priv->dm_name != NULL && g_str_has_prefix (d->priv->dm_name, "udisks-luks-uuid-"))
 
11972
            {
 
11973
 
 
11974
              g_print ("**** NOTE: Force luks teardown device %s (cleartext %s)\n",
 
11975
                       device->priv->device_file,
 
11976
                       d->priv->device_file);
 
11977
 
 
11978
              /* Gotcha */
 
11979
              force_luks_teardown (device, d, callback, user_data);
 
11980
              goto pending;
 
11981
            }
 
11982
        }
 
11983
    }
 
11984
 
 
11985
  /* nothing to force remove */
 
11986
  if (callback != NULL)
 
11987
    callback (device, TRUE, user_data);
 
11988
 
 
11989
 pending:
 
11990
  ;
 
11991
}
 
11992
 
 
11993
/*--------------------------------------------------------------------------------------------------------------*/
 
11994
 
 
11995
static void
 
11996
polling_inhibitor_disconnected_cb (Inhibitor *inhibitor,
 
11997
                                   Device *device)
 
11998
{
 
11999
  device->priv->polling_inhibitors = g_list_remove (device->priv->polling_inhibitors, inhibitor);
 
12000
  g_signal_handlers_disconnect_by_func (inhibitor, polling_inhibitor_disconnected_cb, device);
 
12001
  g_object_unref (inhibitor);
 
12002
 
 
12003
  update_info (device);
 
12004
  drain_pending_changes (device, FALSE);
 
12005
  daemon_local_update_poller (device->priv->daemon);
 
12006
}
 
12007
 
 
12008
static void
 
12009
device_drive_inhibit_polling_authorized_cb (Daemon *daemon,
 
12010
                                            Device *device,
 
12011
                                            DBusGMethodInvocation *context,
 
12012
                                            const gchar *action_id,
 
12013
                                            guint num_user_data,
 
12014
                                            gpointer *user_data_elements)
 
12015
{
 
12016
  gchar **options = user_data_elements[0];
 
12017
  Inhibitor *inhibitor;
 
12018
  guint n;
 
12019
 
 
12020
  for (n = 0; options[n] != NULL; n++)
 
12021
    {
 
12022
      const char *option = options[n];
 
12023
      throw_error (context, ERROR_INVALID_OPTION, "Unknown option %s", option);
 
12024
      goto out;
 
12025
    }
 
12026
 
 
12027
  inhibitor = inhibitor_new (context);
 
12028
 
 
12029
  device->priv->polling_inhibitors = g_list_prepend (device->priv->polling_inhibitors, inhibitor);
 
12030
  g_signal_connect (inhibitor, "disconnected", G_CALLBACK (polling_inhibitor_disconnected_cb), device);
 
12031
 
 
12032
  update_info (device);
 
12033
  drain_pending_changes (device, FALSE);
 
12034
  daemon_local_update_poller (device->priv->daemon);
 
12035
 
 
12036
  dbus_g_method_return (context, inhibitor_get_cookie (inhibitor));
 
12037
 
 
12038
 out:
 
12039
  ;
 
12040
}
 
12041
 
 
12042
gboolean
 
12043
device_drive_inhibit_polling (Device *device,
 
12044
                              char **options,
 
12045
                              DBusGMethodInvocation *context)
 
12046
{
 
12047
  if (!device->priv->device_is_drive)
 
12048
    {
 
12049
      throw_error (context, ERROR_FAILED, "Device is not a drive");
 
12050
      goto out;
 
12051
    }
 
12052
 
 
12053
  if (!device->priv->device_is_media_change_detection_inhibitable)
 
12054
    {
 
12055
      throw_error (context, ERROR_FAILED, "Media detection cannot be inhibited");
 
12056
      goto out;
 
12057
    }
 
12058
 
 
12059
  daemon_local_check_auth (device->priv->daemon,
 
12060
                           device,
 
12061
                           "org.freedesktop.udisks.inhibit-polling",
 
12062
                           "DriveInhibitPolling",
 
12063
                           TRUE,
 
12064
                           device_drive_inhibit_polling_authorized_cb,
 
12065
                           context,
 
12066
                           1,
 
12067
                           g_strdupv (options),
 
12068
                           g_strfreev);
 
12069
 
 
12070
 out:
 
12071
  return TRUE;
 
12072
}
 
12073
 
 
12074
/*--------------------------------------------------------------------------------------------------------------*/
 
12075
 
 
12076
gboolean
 
12077
device_drive_uninhibit_polling (Device *device,
 
12078
                                char *cookie,
 
12079
                                DBusGMethodInvocation *context)
 
12080
{
 
12081
  const gchar *sender;
 
12082
  Inhibitor *inhibitor;
 
12083
  GList *l;
 
12084
 
 
12085
  sender = dbus_g_method_get_sender (context);
 
12086
 
 
12087
  inhibitor = NULL;
 
12088
  for (l = device->priv->polling_inhibitors; l != NULL; l = l->next)
 
12089
    {
 
12090
      Inhibitor *i = INHIBITOR (l->data);
 
12091
 
 
12092
      if (g_strcmp0 (inhibitor_get_unique_dbus_name (i), sender) == 0 && g_strcmp0 (inhibitor_get_cookie (i), cookie)
 
12093
          == 0)
 
12094
        {
 
12095
          inhibitor = i;
 
12096
          break;
 
12097
        }
 
12098
    }
 
12099
 
 
12100
  if (inhibitor == NULL)
 
12101
    {
 
12102
      throw_error (context, ERROR_FAILED, "No such inhibitor");
 
12103
      goto out;
 
12104
    }
 
12105
 
 
12106
  device->priv->polling_inhibitors = g_list_remove (device->priv->polling_inhibitors, inhibitor);
 
12107
  g_object_unref (inhibitor);
 
12108
 
 
12109
  update_info (device);
 
12110
  drain_pending_changes (device, FALSE);
 
12111
  daemon_local_update_poller (device->priv->daemon);
 
12112
 
 
12113
  dbus_g_method_return (context);
 
12114
 
 
12115
 out:
 
12116
  return TRUE;
 
12117
}
 
12118
 
 
12119
/*--------------------------------------------------------------------------------------------------------------*/
 
12120
 
 
12121
static void
 
12122
drive_poll_media_completed_cb (DBusGMethodInvocation *context,
 
12123
                               Device *device,
 
12124
                               gboolean job_was_cancelled,
 
12125
                               int status,
 
12126
                               const char *stderr,
 
12127
                               const char *stdout,
 
12128
                               gpointer user_data)
 
12129
{
 
12130
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
12131
    {
 
12132
 
 
12133
      device_generate_kernel_change_event (device);
 
12134
 
 
12135
      dbus_g_method_return (context);
 
12136
    }
 
12137
  else
 
12138
    {
 
12139
      if (job_was_cancelled)
 
12140
        {
 
12141
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
12142
        }
 
12143
      else
 
12144
        {
 
12145
          throw_error (context,
 
12146
                       ERROR_FAILED,
 
12147
                       "Error detaching: helper exited with exit code %d: %s",
 
12148
                       WEXITSTATUS (status),
 
12149
                       stderr);
 
12150
        }
 
12151
    }
 
12152
}
 
12153
 
 
12154
static void
 
12155
device_drive_poll_media_authorized_cb (Daemon *daemon,
 
12156
                                       Device *device,
 
12157
                                       DBusGMethodInvocation *context,
 
12158
                                       const gchar *action_id,
 
12159
                                       guint num_user_data,
 
12160
                                       gpointer *user_data_elements)
 
12161
{
 
12162
  int n;
 
12163
  char *argv[16];
 
12164
 
 
12165
  n = 0;
 
12166
  argv[n++] = "udisks-helper-drive-poll";
 
12167
  argv[n++] = device->priv->device_file;
 
12168
  argv[n++] = NULL;
 
12169
 
 
12170
  if (!job_new (context, "DrivePollMedia", FALSE, device, argv, NULL, drive_poll_media_completed_cb, FALSE, NULL, NULL))
 
12171
    {
 
12172
      goto out;
 
12173
    }
 
12174
 
 
12175
 out:
 
12176
  ;
 
12177
}
 
12178
 
 
12179
gboolean
 
12180
device_drive_poll_media (Device *device,
 
12181
                         DBusGMethodInvocation *context)
 
12182
{
 
12183
  if (!device->priv->device_is_drive)
 
12184
    {
 
12185
      throw_error (context, ERROR_FAILED, "Device is not a drive");
 
12186
      goto out;
 
12187
    }
 
12188
 
 
12189
  daemon_local_check_auth (device->priv->daemon,
 
12190
                           device,
 
12191
                           "org.freedesktop.udisks.inhibit-polling",
 
12192
                           "DrivePollMedia",
 
12193
                           TRUE,
 
12194
                           device_drive_poll_media_authorized_cb,
 
12195
                           context,
 
12196
                           0);
 
12197
 out:
 
12198
  return TRUE;
 
12199
}
 
12200
 
 
12201
/*--------------------------------------------------------------------------------------------------------------*/
 
12202
 
 
12203
static void
 
12204
spindown_inhibitor_disconnected_cb (Inhibitor *inhibitor,
 
12205
                                    Device *device)
 
12206
{
 
12207
  device->priv->spindown_inhibitors = g_list_remove (device->priv->spindown_inhibitors, inhibitor);
 
12208
  g_signal_handlers_disconnect_by_func (inhibitor, spindown_inhibitor_disconnected_cb, device);
 
12209
  g_object_unref (inhibitor);
 
12210
 
 
12211
  update_info (device);
 
12212
  drain_pending_changes (device, FALSE);
 
12213
  daemon_local_update_spindown (device->priv->daemon);
 
12214
}
 
12215
 
 
12216
static void
 
12217
device_drive_set_spindown_timeout_authorized_cb (Daemon *daemon,
 
12218
                                                 Device *device,
 
12219
                                                 DBusGMethodInvocation *context,
 
12220
                                                 const gchar *action_id,
 
12221
                                                 guint num_user_data,
 
12222
                                                 gpointer *user_data_elements)
 
12223
{
 
12224
  gint timeout_seconds = GPOINTER_TO_INT (user_data_elements[0]);
 
12225
  gchar **options = user_data_elements[1];
 
12226
  Inhibitor *inhibitor;
 
12227
  guint n;
 
12228
 
 
12229
  if (!device->priv->device_is_drive)
 
12230
    {
 
12231
      throw_error (context, ERROR_FAILED, "Device is not a drive");
 
12232
      goto out;
 
12233
    }
 
12234
 
 
12235
  if (!device->priv->drive_can_spindown)
 
12236
    {
 
12237
      throw_error (context, ERROR_FAILED, "Cannot spindown device");
 
12238
      goto out;
 
12239
    }
 
12240
 
 
12241
  if (timeout_seconds < 1)
 
12242
    {
 
12243
      throw_error (context, ERROR_FAILED, "Timeout seconds must be at least 1");
 
12244
      goto out;
 
12245
    }
 
12246
 
 
12247
  for (n = 0; options[n] != NULL; n++)
 
12248
    {
 
12249
      const char *option = options[n];
 
12250
      throw_error (context, ERROR_INVALID_OPTION, "Unknown option %s", option);
 
12251
      goto out;
 
12252
    }
 
12253
 
 
12254
  inhibitor = inhibitor_new (context);
 
12255
 
 
12256
  g_object_set_data (G_OBJECT (inhibitor), "spindown-timeout-seconds", GINT_TO_POINTER (timeout_seconds));
 
12257
 
 
12258
  device->priv->spindown_inhibitors = g_list_prepend (device->priv->spindown_inhibitors, inhibitor);
 
12259
  g_signal_connect (inhibitor, "disconnected", G_CALLBACK (spindown_inhibitor_disconnected_cb), device);
 
12260
 
 
12261
  update_info (device);
 
12262
  drain_pending_changes (device, FALSE);
 
12263
  daemon_local_update_spindown (device->priv->daemon);
 
12264
 
 
12265
  dbus_g_method_return (context, inhibitor_get_cookie (inhibitor));
 
12266
 
 
12267
 out:
 
12268
  ;
 
12269
}
 
12270
 
 
12271
gboolean
 
12272
device_drive_set_spindown_timeout (Device *device,
 
12273
                                   int timeout_seconds,
 
12274
                                   char **options,
 
12275
                                   DBusGMethodInvocation *context)
 
12276
{
 
12277
  if (!device->priv->device_is_drive)
 
12278
    {
 
12279
      throw_error (context, ERROR_FAILED, "Device is not a drive");
 
12280
      goto out;
 
12281
    }
 
12282
 
 
12283
  if (!device->priv->drive_can_spindown)
 
12284
    {
 
12285
      throw_error (context, ERROR_FAILED, "Cannot spindown device");
 
12286
      goto out;
 
12287
    }
 
12288
 
 
12289
  if (timeout_seconds < 1)
 
12290
    {
 
12291
      throw_error (context, ERROR_FAILED, "Timeout seconds must be at least 1");
 
12292
      goto out;
 
12293
    }
 
12294
 
 
12295
  daemon_local_check_auth (device->priv->daemon,
 
12296
                           device,
 
12297
                           "org.freedesktop.udisks.drive-set-spindown",
 
12298
                           "DriveSetSpindownTimeout",
 
12299
                           TRUE,
 
12300
                           device_drive_set_spindown_timeout_authorized_cb,
 
12301
                           context,
 
12302
                           2,
 
12303
                           GINT_TO_POINTER (timeout_seconds),
 
12304
                           NULL,
 
12305
                           g_strdupv (options),
 
12306
                           g_strfreev);
 
12307
 
 
12308
 out:
 
12309
  return TRUE;
 
12310
}
 
12311
 
 
12312
/*--------------------------------------------------------------------------------------------------------------*/
 
12313
 
 
12314
gboolean
 
12315
device_drive_unset_spindown_timeout (Device *device,
 
12316
                                     char *cookie,
 
12317
                                     DBusGMethodInvocation *context)
 
12318
{
 
12319
  const gchar *sender;
 
12320
  Inhibitor *inhibitor;
 
12321
  GList *l;
 
12322
 
 
12323
  sender = dbus_g_method_get_sender (context);
 
12324
 
 
12325
  inhibitor = NULL;
 
12326
  for (l = device->priv->spindown_inhibitors; l != NULL; l = l->next)
 
12327
    {
 
12328
      Inhibitor *i = INHIBITOR (l->data);
 
12329
 
 
12330
      if (g_strcmp0 (inhibitor_get_unique_dbus_name (i), sender) == 0 && g_strcmp0 (inhibitor_get_cookie (i), cookie)
 
12331
          == 0)
 
12332
        {
 
12333
          inhibitor = i;
 
12334
          break;
 
12335
        }
 
12336
    }
 
12337
 
 
12338
  if (inhibitor == NULL)
 
12339
    {
 
12340
      throw_error (context, ERROR_FAILED, "No such spindown configurator");
 
12341
      goto out;
 
12342
    }
 
12343
 
 
12344
  device->priv->spindown_inhibitors = g_list_remove (device->priv->spindown_inhibitors, inhibitor);
 
12345
  g_object_unref (inhibitor);
 
12346
 
 
12347
  update_info (device);
 
12348
  drain_pending_changes (device, FALSE);
 
12349
  daemon_local_update_spindown (device->priv->daemon);
 
12350
 
 
12351
  dbus_g_method_return (context);
 
12352
 
 
12353
 out:
 
12354
  return TRUE;
 
12355
}
 
12356
 
 
12357
/*--------------------------------------------------------------------------------------------------------------*/
 
12358
 
 
12359
static void
 
12360
drive_benchmark_completed_cb (DBusGMethodInvocation *context,
 
12361
                              Device *device,
 
12362
                              gboolean job_was_cancelled,
 
12363
                              int status,
 
12364
                              const gchar *stderr,
 
12365
                              const gchar *stdout,
 
12366
                              gpointer user_data)
 
12367
{
 
12368
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
12369
    {
 
12370
      GPtrArray *read_transfer_rate_array;
 
12371
      GPtrArray *write_transfer_rate_array;
 
12372
      GPtrArray *access_time_array;
 
12373
      gchar **lines;
 
12374
      guint n;
 
12375
      GType elem_gtype;
 
12376
 
 
12377
      elem_gtype = dbus_g_type_get_struct ("GValueArray", G_TYPE_UINT64, G_TYPE_DOUBLE, G_TYPE_INVALID);
 
12378
 
 
12379
      read_transfer_rate_array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_value_array_free);
 
12380
      write_transfer_rate_array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_value_array_free);
 
12381
      access_time_array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_value_array_free);
 
12382
 
 
12383
      lines = g_strsplit (stdout, "\n", 0);
 
12384
      for (n = 0; lines != NULL && lines[n] != NULL; n++)
 
12385
        {
 
12386
          const gchar *line = lines[n];
 
12387
          guint64 offset;
 
12388
          gdouble rate;
 
12389
          gdouble access_time;
 
12390
          GValue elem =
 
12391
            { 0 };
 
12392
 
 
12393
          if (sscanf (line, "read_transfer_rate: offset %" G_GUINT64_FORMAT " rate %lf",
 
12394
                      &offset,
 
12395
                      &rate) == 2)
 
12396
            {
 
12397
 
 
12398
              g_value_init (&elem, elem_gtype);
 
12399
              g_value_take_boxed (&elem, dbus_g_type_specialized_construct (elem_gtype));
 
12400
              dbus_g_type_struct_set (&elem, 0, offset, 1, rate, G_MAXUINT);
 
12401
              g_ptr_array_add (read_transfer_rate_array, g_value_get_boxed (&elem));
 
12402
 
 
12403
            }
 
12404
          else if (sscanf (line, "write_transfer_rate: offset %" G_GUINT64_FORMAT " rate %lf",
 
12405
                           &offset,
 
12406
                           &rate) == 2)
 
12407
            {
 
12408
 
 
12409
              g_value_init (&elem, elem_gtype);
 
12410
              g_value_take_boxed (&elem, dbus_g_type_specialized_construct (elem_gtype));
 
12411
              dbus_g_type_struct_set (&elem, 0, offset, 1, rate, G_MAXUINT);
 
12412
              g_ptr_array_add (write_transfer_rate_array, g_value_get_boxed (&elem));
 
12413
 
 
12414
            }
 
12415
          else if (sscanf (line, "access_time: offset %" G_GUINT64_FORMAT " time %lf",
 
12416
                           &offset,
 
12417
                           &access_time) == 2)
 
12418
            {
 
12419
 
 
12420
              g_value_init (&elem, elem_gtype);
 
12421
              g_value_take_boxed (&elem, dbus_g_type_specialized_construct (elem_gtype));
 
12422
              dbus_g_type_struct_set (&elem, 0, offset, 1, access_time, G_MAXUINT);
 
12423
              g_ptr_array_add (access_time_array, g_value_get_boxed (&elem));
 
12424
 
 
12425
            }
 
12426
          else
 
12427
            {
 
12428
              g_warning ("unhandled line %d: `%s'", n, line);
 
12429
            }
 
12430
 
 
12431
        }
 
12432
      g_strfreev (lines);
 
12433
 
 
12434
      dbus_g_method_return (context, read_transfer_rate_array, write_transfer_rate_array, access_time_array);
 
12435
 
 
12436
      g_ptr_array_unref (read_transfer_rate_array);
 
12437
      g_ptr_array_unref (write_transfer_rate_array);
 
12438
      g_ptr_array_unref (access_time_array);
 
12439
    }
 
12440
  else
 
12441
    {
 
12442
      if (job_was_cancelled)
 
12443
        {
 
12444
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
12445
        }
 
12446
      else
 
12447
        {
 
12448
          throw_error (context,
 
12449
                       ERROR_FAILED,
 
12450
                       "Error benchmarking: helper exited with exit code %d: %s",
 
12451
                       WEXITSTATUS (status),
 
12452
                       stderr);
 
12453
        }
 
12454
    }
 
12455
}
 
12456
 
 
12457
static void
 
12458
device_drive_benchmark_authorized_cb (Daemon *daemon,
 
12459
                                      Device *device,
 
12460
                                      DBusGMethodInvocation *context,
 
12461
                                      const gchar *action_id,
 
12462
                                      guint num_user_data,
 
12463
                                      gpointer *user_data_elements)
 
12464
{
 
12465
  gboolean do_write_benchmark = GPOINTER_TO_INT (user_data_elements[0]);
 
12466
  gchar **options = user_data_elements[1];
 
12467
  gchar *argv[16];
 
12468
  guint n;
 
12469
 
 
12470
  if (!device->priv->device_is_drive)
 
12471
    {
 
12472
      throw_error (context, ERROR_FAILED, "Device is not a drive");
 
12473
      goto out;
 
12474
    }
 
12475
 
 
12476
  if (do_write_benchmark)
 
12477
    {
 
12478
      if (device->priv->device_is_partition_table)
 
12479
        {
 
12480
          throw_error (context, ERROR_FAILED, "A partition table was detected - write benchmarking requires "
 
12481
                       "the disk to be completely empty");
 
12482
          goto out;
 
12483
        }
 
12484
 
 
12485
      if (device->priv->id_usage != NULL)
 
12486
        {
 
12487
          throw_error (context, ERROR_FAILED, "The disk seems to have usage `%s' - write benchmarking requires "
 
12488
                       "the disk to be completely empty", device->priv->id_usage);
 
12489
          goto out;
 
12490
        }
 
12491
    }
 
12492
 
 
12493
  for (n = 0; options[n] != NULL; n++)
 
12494
    {
 
12495
      const char *option = options[n];
 
12496
      throw_error (context, ERROR_INVALID_OPTION, "Unknown option %s", option);
 
12497
      goto out;
 
12498
    }
 
12499
 
 
12500
  n = 0;
 
12501
  argv[n++] = "udisks-helper-drive-benchmark";
 
12502
  argv[n++] = device->priv->device_file;
 
12503
  argv[n++] = do_write_benchmark ? "1" : "0";
 
12504
  argv[n++] = NULL;
 
12505
 
 
12506
  if (!job_new (context, "DriveBenchmark", TRUE, device, argv, NULL, drive_benchmark_completed_cb, FALSE, NULL, NULL))
 
12507
    {
 
12508
      goto out;
 
12509
    }
 
12510
 
 
12511
 out:
 
12512
  ;
 
12513
}
 
12514
 
 
12515
gboolean
 
12516
device_drive_benchmark (Device *device,
 
12517
                        gboolean do_write_benchmark,
 
12518
                        char **options,
 
12519
                        DBusGMethodInvocation *context)
 
12520
{
 
12521
  if (!device->priv->device_is_drive)
 
12522
    {
 
12523
      throw_error (context, ERROR_FAILED, "Device is not a drive");
 
12524
      goto out;
 
12525
    }
 
12526
 
 
12527
  daemon_local_check_auth (device->priv->daemon,
 
12528
                           device,
 
12529
                           "org.freedesktop.udisks.change",
 
12530
                           "DriveBenchmark",
 
12531
                           TRUE,
 
12532
                           device_drive_benchmark_authorized_cb,
 
12533
                           context,
 
12534
                           2,
 
12535
                           GINT_TO_POINTER (do_write_benchmark),
 
12536
                           NULL,
 
12537
                           g_strdupv (options),
 
12538
                           g_strfreev);
 
12539
 
 
12540
 out:
 
12541
  return TRUE;
 
12542
}
 
12543
 
 
12544
/*--------------------------------------------------------------------------------------------------------------*/
 
12545
 
 
12546
static const gchar *
 
12547
find_lvm2_vg_name_for_uuid (Daemon *daemon,
 
12548
                            const gchar *uuid)
 
12549
{
 
12550
  GList *l;
 
12551
  GList *devices;
 
12552
  const gchar *vg_name;
 
12553
 
 
12554
  vg_name = NULL;
 
12555
 
 
12556
  devices = daemon_local_get_all_devices (daemon);
 
12557
  for (l = devices; l != NULL; l = l->next)
 
12558
    {
 
12559
      Device *d = DEVICE (l->data);
 
12560
 
 
12561
      if (d->priv->device_is_linux_lvm2_pv && g_strcmp0 (uuid, d->priv->linux_lvm2_pv_group_uuid) == 0)
 
12562
        {
 
12563
          vg_name = d->priv->linux_lvm2_pv_group_name;
 
12564
          break;
 
12565
        }
 
12566
    }
 
12567
  g_list_free (devices);
 
12568
 
 
12569
  return vg_name;
 
12570
}
 
12571
 
 
12572
/*--------------------------------------------------------------------------------------------------------------*/
 
12573
 
 
12574
static void
 
12575
linux_lvm2_vg_stop_completed_cb (DBusGMethodInvocation *context,
 
12576
                                 Device *device,
 
12577
                                 gboolean job_was_cancelled,
 
12578
                                 int status,
 
12579
                                 const char *stderr,
 
12580
                                 const char *stdout,
 
12581
                                 gpointer user_data)
 
12582
{
 
12583
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
12584
    {
 
12585
      dbus_g_method_return (context);
 
12586
    }
 
12587
  else
 
12588
    {
 
12589
      if (job_was_cancelled)
 
12590
        {
 
12591
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
12592
        }
 
12593
      else
 
12594
        {
 
12595
          throw_error (context,
 
12596
                       ERROR_FAILED,
 
12597
                       "Error stopping LVM2 Volume Group: vgchange exited with exit code %d: %s",
 
12598
                       WEXITSTATUS (status),
 
12599
                       stderr);
 
12600
        }
 
12601
    }
 
12602
}
 
12603
 
 
12604
static void
 
12605
daemon_linux_lvm2_vg_stop_authorized_cb (Daemon *daemon,
 
12606
                                         Device *device,
 
12607
                                         DBusGMethodInvocation *context,
 
12608
                                         const gchar *action_id,
 
12609
                                         guint num_user_data,
 
12610
                                         gpointer *user_data_elements)
 
12611
{
 
12612
  const gchar *uuid = user_data_elements[0];
 
12613
  const gchar *vg_name;
 
12614
  /* TODO: use options */
 
12615
  //gchar **options            = user_data_elements[1];
 
12616
  guint n;
 
12617
  gchar *argv[10];
 
12618
 
 
12619
  /* Unfortunately vgchange does not (yet - file a bug) accept UUIDs - so find the VG name for this
 
12620
   * UUID by looking at PVs
 
12621
   */
 
12622
  vg_name = find_lvm2_vg_name_for_uuid (daemon, uuid);
 
12623
  if (vg_name == NULL)
 
12624
    {
 
12625
      throw_error (context, ERROR_FAILED, "Cannot find VG with UUID `%s'", uuid);
 
12626
      goto out;
 
12627
    }
 
12628
 
 
12629
  n = 0;
 
12630
  argv[n++] = "vgchange";
 
12631
  argv[n++] = "-an";
 
12632
  argv[n++] = (gchar *) vg_name;
 
12633
  argv[n++] = NULL;
 
12634
 
 
12635
  if (!job_new (context, "LinuxLvm2VGStop", TRUE, NULL, argv, NULL, linux_lvm2_vg_stop_completed_cb, FALSE, NULL, NULL))
 
12636
    {
 
12637
      goto out;
 
12638
    }
 
12639
 
 
12640
 out:
 
12641
  ;
 
12642
}
 
12643
 
 
12644
gboolean
 
12645
daemon_linux_lvm2_vg_stop (Daemon *daemon,
 
12646
                           const gchar *uuid,
 
12647
                           char **options,
 
12648
                           DBusGMethodInvocation *context)
 
12649
{
 
12650
  daemon_local_check_auth (daemon,
 
12651
                           NULL,
 
12652
                           "org.freedesktop.udisks.linux-lvm2",
 
12653
                           "LinuxLvm2VGStop",
 
12654
                           TRUE,
 
12655
                           daemon_linux_lvm2_vg_stop_authorized_cb,
 
12656
                           context,
 
12657
                           2,
 
12658
                           g_strdup (uuid),
 
12659
                           g_free,
 
12660
                           g_strdupv (options),
 
12661
                           g_strfreev);
 
12662
 
 
12663
  return TRUE;
 
12664
}
 
12665
 
 
12666
/*--------------------------------------------------------------------------------------------------------------*/
 
12667
 
 
12668
static void
 
12669
linux_lvm2_vg_start_completed_cb (DBusGMethodInvocation *context,
 
12670
                                  Device *device,
 
12671
                                  gboolean job_was_cancelled,
 
12672
                                  int status,
 
12673
                                  const char *stderr,
 
12674
                                  const char *stdout,
 
12675
                                  gpointer user_data)
 
12676
{
 
12677
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
12678
    {
 
12679
      dbus_g_method_return (context);
 
12680
    }
 
12681
  else
 
12682
    {
 
12683
      if (job_was_cancelled)
 
12684
        {
 
12685
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
12686
        }
 
12687
      else
 
12688
        {
 
12689
          throw_error (context,
 
12690
                       ERROR_FAILED,
 
12691
                       "Error starting LVM2 Volume Group: vgchange exited with exit code %d: %s",
 
12692
                       WEXITSTATUS (status),
 
12693
                       stderr);
 
12694
        }
 
12695
    }
 
12696
}
 
12697
 
 
12698
static void
 
12699
daemon_linux_lvm2_vg_start_authorized_cb (Daemon *daemon,
 
12700
                                          Device *device,
 
12701
                                          DBusGMethodInvocation *context,
 
12702
                                          const gchar *action_id,
 
12703
                                          guint num_user_data,
 
12704
                                          gpointer *user_data_elements)
 
12705
{
 
12706
  const gchar *uuid = user_data_elements[0];
 
12707
  const gchar *vg_name;
 
12708
  /* TODO: use options */
 
12709
  //gchar **options            = user_data_elements[1];
 
12710
  guint n;
 
12711
  gchar *argv[10];
 
12712
 
 
12713
  /* Unfortunately vgchange does not (yet - file a bug) accept UUIDs - so find the VG name for this
 
12714
   * UUID by looking at PVs
 
12715
   */
 
12716
 
 
12717
  vg_name = find_lvm2_vg_name_for_uuid (daemon, uuid);
 
12718
  if (vg_name == NULL)
 
12719
    {
 
12720
      throw_error (context, ERROR_FAILED, "Cannot find VG with UUID `%s'", uuid);
 
12721
      goto out;
 
12722
    }
 
12723
 
 
12724
  n = 0;
 
12725
  argv[n++] = "vgchange";
 
12726
  argv[n++] = "-ay";
 
12727
  argv[n++] = (gchar *) vg_name;
 
12728
  argv[n++] = NULL;
 
12729
 
 
12730
  if (!job_new (context, "LinuxLvm2VGStart", TRUE, NULL, argv, NULL, linux_lvm2_vg_start_completed_cb, FALSE, NULL, NULL))
 
12731
    {
 
12732
      goto out;
 
12733
    }
 
12734
 
 
12735
 out:
 
12736
  ;
 
12737
}
 
12738
 
 
12739
gboolean
 
12740
daemon_linux_lvm2_vg_start (Daemon *daemon,
 
12741
                            const gchar *uuid,
 
12742
                            char **options,
 
12743
                            DBusGMethodInvocation *context)
 
12744
{
 
12745
  daemon_local_check_auth (daemon,
 
12746
                           NULL,
 
12747
                           "org.freedesktop.udisks.linux-lvm2",
 
12748
                           "LinuxLvm2VGStart",
 
12749
                           TRUE,
 
12750
                           daemon_linux_lvm2_vg_start_authorized_cb,
 
12751
                           context,
 
12752
                           2,
 
12753
                           g_strdup (uuid),
 
12754
                           g_free,
 
12755
                           g_strdupv (options),
 
12756
                           g_strfreev);
 
12757
 
 
12758
  return TRUE;
 
12759
}
 
12760
 
 
12761
/*--------------------------------------------------------------------------------------------------------------*/
 
12762
 
 
12763
static gchar *
 
12764
find_lvm2_lv_name_for_uuids (Daemon *daemon,
 
12765
                             const gchar *group_uuid,
 
12766
                             const gchar *uuid)
 
12767
{
 
12768
  GList *l;
 
12769
  GList *devices;
 
12770
  gchar *ret;
 
12771
 
 
12772
  ret = NULL;
 
12773
 
 
12774
  devices = daemon_local_get_all_devices (daemon);
 
12775
  for (l = devices; l != NULL; l = l->next)
 
12776
    {
 
12777
      Device *d = DEVICE (l->data);
 
12778
 
 
12779
      if (d->priv->device_is_linux_lvm2_pv &&
 
12780
          g_strcmp0 (group_uuid, d->priv->linux_lvm2_pv_group_uuid) == 0)
 
12781
        {
 
12782
          guint n;
 
12783
 
 
12784
          for (n = 0; n < d->priv->linux_lvm2_pv_group_logical_volumes->len; n++)
 
12785
            {
 
12786
              const gchar *lv_data = d->priv->linux_lvm2_pv_group_logical_volumes->pdata[n];
 
12787
              gchar **tokens;
 
12788
              guint m;
 
12789
 
 
12790
              tokens = g_strsplit (lv_data, ";", 0);
 
12791
              for (m = 0; tokens != NULL && tokens[m] != NULL; m++)
 
12792
                {
 
12793
                  if (g_str_has_prefix (tokens[m], "uuid=") && g_strcmp0 (tokens[m] + 5, uuid) == 0)
 
12794
                    {
 
12795
                      guint c;
 
12796
                      for (c = 0; tokens[c] != NULL; c++)
 
12797
                        {
 
12798
                          if (g_str_has_prefix (tokens[c], "name="))
 
12799
                            {
 
12800
                              ret = g_strdup_printf ("%s/%s",
 
12801
                                                     d->priv->linux_lvm2_pv_group_name,
 
12802
                                                     tokens[c] + 5);
 
12803
                              break;
 
12804
                            }
 
12805
                        }
 
12806
                    }
 
12807
                }
 
12808
              g_strfreev (tokens);
 
12809
 
 
12810
              if (ret != NULL)
 
12811
                break;
 
12812
            }
 
12813
        }
 
12814
      if (ret != NULL)
 
12815
        break;
 
12816
    }
 
12817
  g_list_free (devices);
 
12818
 
 
12819
  return ret;
 
12820
}
 
12821
 
 
12822
 
 
12823
/*--------------------------------------------------------------------------------------------------------------*/
 
12824
 
 
12825
static void
 
12826
linux_lvm2_lv_start_completed_cb (DBusGMethodInvocation *context,
 
12827
                                  Device *device,
 
12828
                                  gboolean job_was_cancelled,
 
12829
                                  int status,
 
12830
                                  const char *stderr,
 
12831
                                  const char *stdout,
 
12832
                                  gpointer user_data)
 
12833
{
 
12834
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
12835
    {
 
12836
      dbus_g_method_return (context);
 
12837
    }
 
12838
  else
 
12839
    {
 
12840
      if (job_was_cancelled)
 
12841
        {
 
12842
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
12843
        }
 
12844
      else
 
12845
        {
 
12846
          throw_error (context,
 
12847
                       ERROR_FAILED,
 
12848
                       "Error starting LVM2 Logical Volume: lvchange exited with exit code %d: %s",
 
12849
                       WEXITSTATUS (status),
 
12850
                       stderr);
 
12851
        }
 
12852
    }
 
12853
}
 
12854
 
 
12855
static void
 
12856
daemon_linux_lvm2_lv_start_authorized_cb (Daemon *daemon,
 
12857
                                          Device *device,
 
12858
                                          DBusGMethodInvocation *context,
 
12859
                                          const gchar *action_id,
 
12860
                                          guint num_user_data,
 
12861
                                          gpointer *user_data_elements)
 
12862
{
 
12863
  const gchar *group_uuid = user_data_elements[0];
 
12864
  const gchar *uuid = user_data_elements[1];
 
12865
  gchar *lv_name;
 
12866
  /* TODO: use options */
 
12867
  //gchar **options            = user_data_elements[2];
 
12868
  guint n;
 
12869
  gchar *argv[10];
 
12870
 
 
12871
  /* Unfortunately vgchange does not (yet - file a bug) accept UUIDs - so find the VG name for this
 
12872
   * UUID by looking at PVs
 
12873
   */
 
12874
 
 
12875
  lv_name = find_lvm2_lv_name_for_uuids (daemon, group_uuid, uuid);
 
12876
  if (lv_name == NULL)
 
12877
    {
 
12878
      throw_error (context, ERROR_FAILED, "Cannot find Logical Volume with Group UUID `%s' and UUID `%s'", group_uuid, uuid);
 
12879
      goto out;
 
12880
    }
 
12881
 
 
12882
  n = 0;
 
12883
  argv[n++] = "lvchange";
 
12884
  argv[n++] = "-ay";
 
12885
  argv[n++] = lv_name;
 
12886
  argv[n++] = NULL;
 
12887
 
 
12888
  if (!job_new (context, "LinuxLvm2LVStart", TRUE, NULL, argv, NULL, linux_lvm2_lv_start_completed_cb, FALSE, NULL, NULL))
 
12889
    {
 
12890
      goto out;
 
12891
    }
 
12892
 
 
12893
 out:
 
12894
  g_free (lv_name);
 
12895
}
 
12896
 
 
12897
gboolean
 
12898
daemon_linux_lvm2_lv_start (Daemon *daemon,
 
12899
                            const gchar *group_uuid,
 
12900
                            const gchar *uuid,
 
12901
                            char **options,
 
12902
                            DBusGMethodInvocation *context)
 
12903
{
 
12904
  daemon_local_check_auth (daemon,
 
12905
                           NULL,
 
12906
                           "org.freedesktop.udisks.linux-lvm2",
 
12907
                           "LinuxLvm2LVStart",
 
12908
                           TRUE,
 
12909
                           daemon_linux_lvm2_lv_start_authorized_cb,
 
12910
                           context,
 
12911
                           3,
 
12912
                           g_strdup (group_uuid),
 
12913
                           g_free,
 
12914
                           g_strdup (uuid),
 
12915
                           g_free,
 
12916
                           g_strdupv (options),
 
12917
                           g_strfreev);
 
12918
 
 
12919
  return TRUE;
 
12920
}
 
12921
 
 
12922
/*--------------------------------------------------------------------------------------------------------------*/
 
12923
 
 
12924
static void
 
12925
linux_lvm2_lv_stop_completed_cb (DBusGMethodInvocation *context,
 
12926
                                 Device *device,
 
12927
                                 gboolean job_was_cancelled,
 
12928
                                 int status,
 
12929
                                 const char *stderr,
 
12930
                                 const char *stdout,
 
12931
                                 gpointer user_data)
 
12932
{
 
12933
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
12934
    {
 
12935
      dbus_g_method_return (context);
 
12936
    }
 
12937
  else
 
12938
    {
 
12939
      if (job_was_cancelled)
 
12940
        {
 
12941
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
12942
        }
 
12943
      else
 
12944
        {
 
12945
          throw_error (context,
 
12946
                       ERROR_FAILED,
 
12947
                       "Error stopping LVM2 Logical Volume: lvchange exited with exit code %d: %s",
 
12948
                       WEXITSTATUS (status),
 
12949
                       stderr);
 
12950
        }
 
12951
    }
 
12952
}
 
12953
 
 
12954
static void
 
12955
daemon_linux_lvm2_lv_stop_authorized_cb (Daemon *daemon,
 
12956
                                         Device *device,
 
12957
                                         DBusGMethodInvocation *context,
 
12958
                                         const gchar *action_id,
 
12959
                                         guint num_user_data,
 
12960
                                         gpointer *user_data_elements)
 
12961
{
 
12962
  gchar *name;
 
12963
  /* TODO: use options */
 
12964
  //gchar **options            = user_data_elements[0];
 
12965
  guint n;
 
12966
  gchar *argv[10];
 
12967
 
 
12968
  name = NULL;
 
12969
 
 
12970
  if (!device->priv->device_is_linux_lvm2_lv)
 
12971
    {
 
12972
      throw_error (context, ERROR_FAILED, "Device is not a Linux LVM2 Logical Volume");
 
12973
      goto out;
 
12974
    }
 
12975
 
 
12976
  /* Unfortunately lvchange does not (yet - file a bug) accept UUIDs
 
12977
   */
 
12978
  name = g_strdup_printf ("%s/%s", device->priv->linux_lvm2_lv_group_name, device->priv->linux_lvm2_lv_name);
 
12979
 
 
12980
  n = 0;
 
12981
  argv[n++] = "lvchange";
 
12982
  argv[n++] = "-an";
 
12983
  argv[n++] = name;
 
12984
  argv[n++] = NULL;
 
12985
 
 
12986
  if (!job_new (context, "LinuxLvm2LVStop", TRUE, NULL, argv, NULL, linux_lvm2_lv_stop_completed_cb, FALSE, NULL, NULL))
 
12987
    {
 
12988
      goto out;
 
12989
    }
 
12990
 
 
12991
 out:
 
12992
  g_free (name);
 
12993
}
 
12994
 
 
12995
gboolean
 
12996
device_linux_lvm2_lv_stop (Device *device,
 
12997
                           char **options,
 
12998
                           DBusGMethodInvocation *context)
 
12999
{
 
13000
  daemon_local_check_auth (device->priv->daemon,
 
13001
                           device,
 
13002
                           "org.freedesktop.udisks.linux-lvm2",
 
13003
                           "LinuxLvm2LVStop",
 
13004
                           TRUE,
 
13005
                           daemon_linux_lvm2_lv_stop_authorized_cb,
 
13006
                           context,
 
13007
                           1,
 
13008
                           g_strdupv (options),
 
13009
                           g_strfreev);
 
13010
 
 
13011
  return TRUE;
 
13012
}
 
13013
 
 
13014
 
 
13015
/*--------------------------------------------------------------------------------------------------------------*/
 
13016
 
 
13017
static void
 
13018
linux_lvm2_vg_set_name_completed_cb (DBusGMethodInvocation *context,
 
13019
                                     Device *device,
 
13020
                                     gboolean job_was_cancelled,
 
13021
                                     int status,
 
13022
                                     const char *stderr,
 
13023
                                     const char *stdout,
 
13024
                                     gpointer user_data)
 
13025
{
 
13026
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
13027
    {
 
13028
      dbus_g_method_return (context);
 
13029
    }
 
13030
  else
 
13031
    {
 
13032
      if (job_was_cancelled)
 
13033
        {
 
13034
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
13035
        }
 
13036
      else
 
13037
        {
 
13038
          throw_error (context,
 
13039
                       ERROR_FAILED,
 
13040
                       "Error setting name for LVM2 Volume Group: vgrename exited with exit code %d: %s",
 
13041
                       WEXITSTATUS (status),
 
13042
                       stderr);
 
13043
        }
 
13044
    }
 
13045
}
 
13046
 
 
13047
static void
 
13048
daemon_linux_lvm2_vg_set_name_authorized_cb (Daemon *daemon,
 
13049
                                             Device *device,
 
13050
                                             DBusGMethodInvocation *context,
 
13051
                                             const gchar *action_id,
 
13052
                                             guint num_user_data,
 
13053
                                             gpointer *user_data_elements)
 
13054
{
 
13055
  const gchar *uuid = user_data_elements[0];
 
13056
  const gchar *new_name = user_data_elements[1];
 
13057
  const gchar *vg_name;
 
13058
  guint n;
 
13059
  gchar *argv[10];
 
13060
 
 
13061
  /* Unfortunately vgchange does not (yet - file a bug) accept UUIDs - so find the VG name for this
 
13062
   * UUID by looking at PVs
 
13063
   */
 
13064
 
 
13065
  vg_name = find_lvm2_vg_name_for_uuid (daemon, uuid);
 
13066
  if (vg_name == NULL)
 
13067
    {
 
13068
      throw_error (context, ERROR_FAILED, "Cannot find VG with UUID `%s'", uuid);
 
13069
      goto out;
 
13070
    }
 
13071
 
 
13072
  n = 0;
 
13073
  argv[n++] = "vgrename";
 
13074
  argv[n++] = (gchar *) vg_name;
 
13075
  argv[n++] = (gchar *) new_name;
 
13076
  argv[n++] = NULL;
 
13077
 
 
13078
  if (!job_new (context, "LinuxLvm2VGSetName", TRUE, NULL, argv, NULL, linux_lvm2_vg_set_name_completed_cb, FALSE, NULL, NULL))
 
13079
    {
 
13080
      goto out;
 
13081
    }
 
13082
 
 
13083
 out:
 
13084
  ;
 
13085
}
 
13086
 
 
13087
gboolean
 
13088
daemon_linux_lvm2_vg_set_name (Daemon *daemon,
 
13089
                               const gchar *uuid,
 
13090
                               const gchar *new_name,
 
13091
                               DBusGMethodInvocation *context)
 
13092
{
 
13093
  daemon_local_check_auth (daemon,
 
13094
                           NULL,
 
13095
                           "org.freedesktop.udisks.linux-lvm2",
 
13096
                           "LinuxLvm2VGSetName",
 
13097
                           TRUE,
 
13098
                           daemon_linux_lvm2_vg_set_name_authorized_cb,
 
13099
                           context,
 
13100
                           2,
 
13101
                           g_strdup (uuid),
 
13102
                           g_free,
 
13103
                           g_strdup (new_name),
 
13104
                           g_free);
 
13105
 
 
13106
  return TRUE;
 
13107
}
 
13108
 
 
13109
/*--------------------------------------------------------------------------------------------------------------*/
 
13110
 
 
13111
static void
 
13112
linux_lvm2_lv_set_name_completed_cb (DBusGMethodInvocation *context,
 
13113
                                     Device *device,
 
13114
                                     gboolean job_was_cancelled,
 
13115
                                     int status,
 
13116
                                     const char *stderr,
 
13117
                                     const char *stdout,
 
13118
                                     gpointer user_data)
 
13119
{
 
13120
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
13121
    {
 
13122
      dbus_g_method_return (context);
 
13123
    }
 
13124
  else
 
13125
    {
 
13126
      if (job_was_cancelled)
 
13127
        {
 
13128
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
13129
        }
 
13130
      else
 
13131
        {
 
13132
          throw_error (context,
 
13133
                       ERROR_FAILED,
 
13134
                       "Error setting name for LVM2 Logical Volume: lvrename exited with exit code %d: %s",
 
13135
                       WEXITSTATUS (status),
 
13136
                       stderr);
 
13137
        }
 
13138
    }
 
13139
}
 
13140
 
 
13141
static void
 
13142
daemon_linux_lvm2_lv_set_name_authorized_cb (Daemon *daemon,
 
13143
                                             Device *device,
 
13144
                                             DBusGMethodInvocation *context,
 
13145
                                             const gchar *action_id,
 
13146
                                             guint num_user_data,
 
13147
                                             gpointer *user_data_elements)
 
13148
{
 
13149
  const gchar *group_uuid = user_data_elements[0];
 
13150
  const gchar *uuid = user_data_elements[1];
 
13151
  const gchar *new_name = user_data_elements[2];
 
13152
  const gchar *vg_name;
 
13153
  gchar *lv_name;
 
13154
  guint n;
 
13155
  gchar *argv[10];
 
13156
 
 
13157
  /* Unfortunately lvchange does not (yet - file a bug) accept UUIDs - so find the LV name for this
 
13158
   * UUID by looking at PVs
 
13159
   */
 
13160
 
 
13161
  lv_name = NULL;
 
13162
 
 
13163
  vg_name = find_lvm2_vg_name_for_uuid (daemon, group_uuid);
 
13164
  if (vg_name == NULL)
 
13165
    {
 
13166
      throw_error (context, ERROR_FAILED, "Cannot find VG with UUID `%s'", group_uuid);
 
13167
      goto out;
 
13168
    }
 
13169
 
 
13170
  lv_name = find_lvm2_lv_name_for_uuids (daemon, group_uuid, uuid);
 
13171
  if (lv_name == NULL)
 
13172
    {
 
13173
      throw_error (context, ERROR_FAILED, "Cannot find LV with UUID `%s'", uuid);
 
13174
      goto out;
 
13175
    }
 
13176
 
 
13177
  n = 0;
 
13178
  argv[n++] = "lvrename";
 
13179
  argv[n++] = (gchar *) vg_name;
 
13180
  argv[n++] = lv_name;
 
13181
  argv[n++] = (gchar *) new_name;
 
13182
  argv[n++] = NULL;
 
13183
 
 
13184
  if (!job_new (context, "LinuxLvm2LVSetName", TRUE, NULL, argv, NULL, linux_lvm2_lv_set_name_completed_cb, FALSE, NULL, NULL))
 
13185
    {
 
13186
      goto out;
 
13187
    }
 
13188
 
 
13189
 out:
 
13190
  g_free (lv_name);
 
13191
}
 
13192
 
 
13193
gboolean
 
13194
daemon_linux_lvm2_lv_set_name (Daemon *daemon,
 
13195
                               const gchar *group_uuid,
 
13196
                               const gchar *uuid,
 
13197
                               const gchar *new_name,
 
13198
                               DBusGMethodInvocation *context)
 
13199
{
 
13200
  daemon_local_check_auth (daemon,
 
13201
                           NULL,
 
13202
                           "org.freedesktop.udisks.linux-lvm2",
 
13203
                           "LinuxLvm2LVSetName",
 
13204
                           TRUE,
 
13205
                           daemon_linux_lvm2_lv_set_name_authorized_cb,
 
13206
                           context,
 
13207
                           3,
 
13208
                           g_strdup (group_uuid),
 
13209
                           g_free,
 
13210
                           g_strdup (uuid),
 
13211
                           g_free,
 
13212
                           g_strdup (new_name),
 
13213
                           g_free);
 
13214
 
 
13215
  return TRUE;
 
13216
}
 
13217
 
 
13218
/*--------------------------------------------------------------------------------------------------------------*/
 
13219
 
 
13220
static void
 
13221
linux_lvm2_lv_remove_completed_cb (DBusGMethodInvocation *context,
 
13222
                                   Device *device,
 
13223
                                   gboolean job_was_cancelled,
 
13224
                                   int status,
 
13225
                                   const char *stderr,
 
13226
                                   const char *stdout,
 
13227
                                   gpointer user_data)
 
13228
{
 
13229
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
13230
    {
 
13231
      dbus_g_method_return (context);
 
13232
    }
 
13233
  else
 
13234
    {
 
13235
      if (job_was_cancelled)
 
13236
        {
 
13237
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
13238
        }
 
13239
      else
 
13240
        {
 
13241
          throw_error (context,
 
13242
                       ERROR_FAILED,
 
13243
                       "Error removing LVM2 Logical Volume: lvremove exited with exit code %d: %s",
 
13244
                       WEXITSTATUS (status),
 
13245
                       stderr);
 
13246
        }
 
13247
    }
 
13248
}
 
13249
 
 
13250
static void
 
13251
daemon_linux_lvm2_lv_remove_authorized_cb (Daemon *daemon,
 
13252
                                           Device *device,
 
13253
                                           DBusGMethodInvocation *context,
 
13254
                                           const gchar *action_id,
 
13255
                                           guint num_user_data,
 
13256
                                           gpointer *user_data_elements)
 
13257
{
 
13258
  const gchar *group_uuid = user_data_elements[0];
 
13259
  const gchar *uuid = user_data_elements[1];
 
13260
  /* TODO: use options: gchar **options = user_data_elements[2]; */
 
13261
  gchar *lv_name;
 
13262
  guint n;
 
13263
  gchar *argv[10];
 
13264
 
 
13265
  /* Unfortunately lvchange does not (yet - file a bug) accept UUIDs - so find the LV name for this
 
13266
   * UUID by looking at PVs
 
13267
   */
 
13268
  lv_name = find_lvm2_lv_name_for_uuids (daemon, group_uuid, uuid);
 
13269
  if (lv_name == NULL)
 
13270
    {
 
13271
      throw_error (context, ERROR_FAILED, "Cannot find LV with UUID `%s'", uuid);
 
13272
      goto out;
 
13273
    }
 
13274
 
 
13275
  n = 0;
 
13276
  argv[n++] = "lvremove";
 
13277
  argv[n++] = lv_name;
 
13278
  argv[n++] = "--force";
 
13279
  argv[n++] = NULL;
 
13280
 
 
13281
  if (!job_new (context, "LinuxLvm2LVRemove", TRUE, NULL, argv, NULL, linux_lvm2_lv_remove_completed_cb, FALSE, NULL, NULL))
 
13282
    {
 
13283
      goto out;
 
13284
    }
 
13285
 
 
13286
 out:
 
13287
  g_free (lv_name);
 
13288
}
 
13289
 
 
13290
gboolean
 
13291
daemon_linux_lvm2_lv_remove (Daemon *daemon,
 
13292
                             const gchar *group_uuid,
 
13293
                             const gchar *uuid,
 
13294
                             gchar **options,
 
13295
                             DBusGMethodInvocation *context)
 
13296
{
 
13297
  daemon_local_check_auth (daemon,
 
13298
                           NULL,
 
13299
                           "org.freedesktop.udisks.linux-lvm2",
 
13300
                           "LinuxLvm2LVRemove",
 
13301
                           TRUE,
 
13302
                           daemon_linux_lvm2_lv_remove_authorized_cb,
 
13303
                           context,
 
13304
                           3,
 
13305
                           g_strdup (group_uuid),
 
13306
                           g_free,
 
13307
                           g_strdup (uuid),
 
13308
                           g_free,
 
13309
                           g_strdupv (options),
 
13310
                           g_strfreev);
 
13311
 
 
13312
  return TRUE;
 
13313
}
 
13314
 
 
13315
/*--------------------------------------------------------------------------------------------------------------*/
 
13316
 
 
13317
typedef struct
 
13318
{
 
13319
  int refcount;
 
13320
 
 
13321
  guint device_added_signal_handler_id;
 
13322
  guint device_changed_signal_handler_id;
 
13323
  guint device_added_timeout_id;
 
13324
 
 
13325
  DBusGMethodInvocation *context;
 
13326
  Daemon *daemon;
 
13327
  gchar *vg_uuid;
 
13328
  gchar *lv_name;
 
13329
 
 
13330
  char *fstype;
 
13331
  char **fsoptions;
 
13332
 
 
13333
} CreateLvm2LVData;
 
13334
 
 
13335
static CreateLvm2LVData *
 
13336
lvm2_lv_create_data_new (DBusGMethodInvocation *context,
 
13337
                         Daemon *daemon,
 
13338
                         const gchar *vg_uuid,
 
13339
                         const gchar *lv_name,
 
13340
                         const char *fstype,
 
13341
                         char **fsoptions)
 
13342
{
 
13343
  CreateLvm2LVData *data;
 
13344
 
 
13345
  data = g_new0 (CreateLvm2LVData, 1);
 
13346
  data->refcount = 1;
 
13347
 
 
13348
  data->context = context;
 
13349
  data->daemon = g_object_ref (daemon);
 
13350
  data->vg_uuid = g_strdup (vg_uuid);
 
13351
  data->lv_name = g_strdup (lv_name);
 
13352
  data->fstype = g_strdup (fstype);
 
13353
  data->fsoptions = g_strdupv (fsoptions);
 
13354
 
 
13355
  return data;
 
13356
}
 
13357
 
 
13358
static CreateLvm2LVData *
 
13359
lvm2_lv_create_data_ref (CreateLvm2LVData *data)
 
13360
{
 
13361
  data->refcount++;
 
13362
  return data;
 
13363
}
 
13364
 
 
13365
static void
 
13366
lvm2_lv_create_data_unref (CreateLvm2LVData *data)
 
13367
{
 
13368
  data->refcount--;
 
13369
  if (data->refcount == 0)
 
13370
    {
 
13371
      g_object_unref (data->daemon);
 
13372
      g_free (data->vg_uuid);
 
13373
      g_free (data->lv_name);
 
13374
      g_free (data->fstype);
 
13375
      g_strfreev (data->fsoptions);
 
13376
      g_free (data);
 
13377
    }
 
13378
}
 
13379
 
 
13380
static void
 
13381
lvm2_lv_create_filesystem_create_hook (DBusGMethodInvocation *context,
 
13382
                                       Device *device,
 
13383
                                       gboolean filesystem_create_succeeded,
 
13384
                                       gpointer user_data)
 
13385
{
 
13386
  if (!filesystem_create_succeeded)
 
13387
    {
 
13388
      /* dang.. FilesystemCreate already reported an error */
 
13389
    }
 
13390
  else
 
13391
    {
 
13392
      /* it worked.. */
 
13393
      dbus_g_method_return (context, device->priv->object_path);
 
13394
    }
 
13395
}
 
13396
 
 
13397
static void
 
13398
lvm2_lv_create_found_device (Device *device,
 
13399
                             CreateLvm2LVData *data)
 
13400
{
 
13401
  if (strlen (data->fstype) > 0)
 
13402
    {
 
13403
      device_filesystem_create_internal (device,
 
13404
                                         data->fstype,
 
13405
                                         data->fsoptions,
 
13406
                                         lvm2_lv_create_filesystem_create_hook,
 
13407
                                         NULL,
 
13408
                                         data->context);
 
13409
    }
 
13410
  else
 
13411
    {
 
13412
      dbus_g_method_return (data->context, device->priv->object_path);
 
13413
    }
 
13414
}
 
13415
 
 
13416
static gboolean
 
13417
str_has_lv_uuid (const gchar *str,
 
13418
                 const gchar *lv_uuid)
 
13419
{
 
13420
  gchar **tokens;
 
13421
  guint n;
 
13422
 
 
13423
  tokens = g_strsplit (str, ";", 0);
 
13424
  for (n = 0; tokens != NULL && tokens[n] != NULL; n++)
 
13425
    {
 
13426
      if (g_str_has_prefix (tokens[n], "uuid=") && g_strcmp0 (tokens[n] + 5, lv_uuid) == 0)
 
13427
        {
 
13428
          return TRUE;
 
13429
        }
 
13430
    }
 
13431
 
 
13432
  return FALSE;
 
13433
}
 
13434
 
 
13435
static Device *
 
13436
lvm2_lv_create_has_lv (CreateLvm2LVData *data)
 
13437
{
 
13438
  GList *devices;
 
13439
  Device *ret;
 
13440
  GList *l;
 
13441
 
 
13442
  ret = NULL;
 
13443
 
 
13444
  devices = daemon_local_get_all_devices (data->daemon);
 
13445
  for (l = devices; l != NULL; l = l->next)
 
13446
    {
 
13447
      Device *d = DEVICE (l->data);
 
13448
      if (d->priv->device_is_linux_lvm2_lv &&
 
13449
          g_strcmp0 (d->priv->linux_lvm2_lv_group_uuid, data->vg_uuid) == 0 &&
 
13450
          g_strcmp0 (d->priv->linux_lvm2_lv_name, data->lv_name) == 0)
 
13451
        {
 
13452
          GList *m;
 
13453
          const gchar *lv_uuid;
 
13454
 
 
13455
          lv_uuid = d->priv->linux_lvm2_lv_uuid;
 
13456
 
 
13457
          /* OK, we've found the LV... now check that one of more PVs actually reference this LV */
 
13458
          for (m = devices; m != NULL; m = m->next)
 
13459
            {
 
13460
              Device *pv = DEVICE (m->data);
 
13461
              if (pv->priv->device_is_linux_lvm2_pv &&
 
13462
                  g_strcmp0 (pv->priv->linux_lvm2_pv_group_uuid, data->vg_uuid) == 0)
 
13463
                {
 
13464
                  guint n;
 
13465
                  for (n = 0; n < pv->priv->linux_lvm2_pv_group_logical_volumes->len; n++)
 
13466
                    {
 
13467
                      const gchar *str = pv->priv->linux_lvm2_pv_group_logical_volumes->pdata[n];
 
13468
                      if (str_has_lv_uuid (str, lv_uuid))
 
13469
                        {
 
13470
                          /* Return the LV, not the PV */
 
13471
                          ret = d;
 
13472
                          break;
 
13473
                        }
 
13474
                    }
 
13475
                }
 
13476
            } /* for all PVs */
 
13477
 
 
13478
          break;
 
13479
        } /* if (found LV) */
 
13480
    }
 
13481
  return ret;
 
13482
}
 
13483
 
 
13484
static void
 
13485
lvm2_lv_create_device_added_cb (Daemon *daemon,
 
13486
                                const char *object_path,
 
13487
                                gpointer user_data)
 
13488
{
 
13489
  CreateLvm2LVData *data = user_data;
 
13490
  Device *device;
 
13491
 
 
13492
  g_debug ("added %s", object_path);
 
13493
 
 
13494
  device = lvm2_lv_create_has_lv (data);
 
13495
  if (device != NULL)
 
13496
    {
 
13497
      /* yay! it is.. now create the file system if requested */
 
13498
      lvm2_lv_create_found_device (device, data);
 
13499
 
 
13500
      g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id);
 
13501
      g_signal_handler_disconnect (daemon, data->device_changed_signal_handler_id);
 
13502
      g_source_remove (data->device_added_timeout_id);
 
13503
      lvm2_lv_create_data_unref (data);
 
13504
    }
 
13505
}
 
13506
 
 
13507
static void
 
13508
lvm2_lv_create_device_changed_cb (Daemon *daemon,
 
13509
                                  const char *object_path,
 
13510
                                  gpointer user_data)
 
13511
{
 
13512
  CreateLvm2LVData *data = user_data;
 
13513
  Device *device;
 
13514
 
 
13515
  g_debug ("changed %s", object_path);
 
13516
 
 
13517
  device = lvm2_lv_create_has_lv (data);
 
13518
  if (device != NULL)
 
13519
    {
 
13520
      /* yay! it is.. now create the file system if requested */
 
13521
      lvm2_lv_create_found_device (device, data);
 
13522
 
 
13523
      g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id);
 
13524
      g_signal_handler_disconnect (daemon, data->device_changed_signal_handler_id);
 
13525
      g_source_remove (data->device_added_timeout_id);
 
13526
      lvm2_lv_create_data_unref (data);
 
13527
    }
 
13528
}
 
13529
 
 
13530
static gboolean
 
13531
lvm2_lv_create_device_not_seen_cb (gpointer user_data)
 
13532
{
 
13533
  CreateLvm2LVData *data = user_data;
 
13534
 
 
13535
  throw_error (data->context,
 
13536
               ERROR_FAILED,
 
13537
               "Error creating Logical Volume: timeout (10s) waiting for LV to show up");
 
13538
 
 
13539
  g_signal_handler_disconnect (data->daemon, data->device_added_signal_handler_id);
 
13540
  g_signal_handler_disconnect (data->daemon, data->device_changed_signal_handler_id);
 
13541
  lvm2_lv_create_data_unref (data);
 
13542
 
 
13543
  return FALSE;
 
13544
}
 
13545
 
 
13546
static void
 
13547
linux_lvm2_lv_create_completed_cb (DBusGMethodInvocation *context,
 
13548
                                   Device *device,
 
13549
                                   gboolean job_was_cancelled,
 
13550
                                   int status,
 
13551
                                   const char *stderr,
 
13552
                                   const char *stdout,
 
13553
                                   gpointer user_data)
 
13554
{
 
13555
  CreateLvm2LVData *data = user_data;
 
13556
 
 
13557
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
13558
    {
 
13559
      Device *d;
 
13560
 
 
13561
      d = lvm2_lv_create_has_lv (data);
 
13562
      if (d != NULL)
 
13563
        {
 
13564
          /* yay! it is.. now create the file system if requested */
 
13565
          lvm2_lv_create_found_device (device, data);
 
13566
        }
 
13567
      else
 
13568
        {
 
13569
          /* otherwise sit around and wait for the new LV to appear */
 
13570
          data->device_added_signal_handler_id = g_signal_connect_after (data->daemon,
 
13571
                                                                         "device-added",
 
13572
                                                                         G_CALLBACK (lvm2_lv_create_device_added_cb),
 
13573
                                                                         data);
 
13574
          data->device_changed_signal_handler_id = g_signal_connect_after (data->daemon,
 
13575
                                                                           "device-changed",
 
13576
                                                                         G_CALLBACK (lvm2_lv_create_device_changed_cb),
 
13577
                                                                           data);
 
13578
          data->device_added_timeout_id = g_timeout_add (10 * 1000,
 
13579
                                                         lvm2_lv_create_device_not_seen_cb,
 
13580
                                                         data);
 
13581
 
 
13582
          lvm2_lv_create_data_ref (data);
 
13583
        }
 
13584
    }
 
13585
  else
 
13586
    {
 
13587
      if (job_was_cancelled)
 
13588
        {
 
13589
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
13590
        }
 
13591
      else
 
13592
        {
 
13593
          throw_error (context,
 
13594
                       ERROR_FAILED,
 
13595
                       "Error creating LVM2 Logical Volume: lvcreate exited with exit code %d: %s",
 
13596
                       WEXITSTATUS (status),
 
13597
                       stderr);
 
13598
        }
 
13599
    }
 
13600
}
 
13601
 
 
13602
static void
 
13603
daemon_linux_lvm2_lv_create_authorized_cb (Daemon *daemon,
 
13604
                                           Device *device,
 
13605
                                           DBusGMethodInvocation *context,
 
13606
                                           const gchar *action_id,
 
13607
                                           guint num_user_data,
 
13608
                                           gpointer *user_data_elements)
 
13609
{
 
13610
  const gchar *group_uuid = user_data_elements[0];
 
13611
  const gchar *name = user_data_elements[1];
 
13612
  guint64 size = *((guint64 *) user_data_elements[2]);
 
13613
  guint num_stripes = GPOINTER_TO_UINT (user_data_elements[3]);
 
13614
  guint64 stripe_size = *((guint64 *) user_data_elements[4]);
 
13615
  guint num_mirrors = GPOINTER_TO_UINT (user_data_elements[5]);
 
13616
  /* TODO: use options: gchar **options = user_data_elements[6]; */
 
13617
  const gchar *fstype = user_data_elements[7];
 
13618
  gchar **fsoptions = user_data_elements[8];
 
13619
  const gchar *vg_name;
 
13620
  gchar **argv;
 
13621
  GString *s;
 
13622
 
 
13623
  argv = NULL;
 
13624
  s = NULL;
 
13625
 
 
13626
  /* Unfortunately lvcreate does not (yet - file a bug) accept UUIDs - so find the VG name for this
 
13627
   * UUID by looking at PVs
 
13628
   */
 
13629
  vg_name = find_lvm2_vg_name_for_uuid (daemon, group_uuid);
 
13630
  if (vg_name == NULL)
 
13631
    {
 
13632
      throw_error (context, ERROR_FAILED, "Cannot find VG with UUID `%s'", group_uuid);
 
13633
      goto out;
 
13634
    }
 
13635
 
 
13636
  if (name == NULL || strlen (name) == 0)
 
13637
    {
 
13638
      throw_error (context, ERROR_FAILED, "Name cannot be blank");
 
13639
      goto out;
 
13640
    }
 
13641
 
 
13642
  if (strstr (name, "\"") != NULL)
 
13643
    {
 
13644
      throw_error (context, ERROR_FAILED, "Name cannot contain the double-quote (\") character");
 
13645
      goto out;
 
13646
    }
 
13647
 
 
13648
  s = g_string_new ("lvcreate ");
 
13649
 
 
13650
  g_string_append_printf (s, "%s ", vg_name);
 
13651
  if (num_stripes > 0)
 
13652
    g_string_append_printf (s, "--stripes %d ", num_stripes);
 
13653
  if (stripe_size > 0)
 
13654
    g_string_append_printf (s, "--stripesize %" G_GUINT64_FORMAT " ", stripe_size);
 
13655
  if (num_mirrors > 0)
 
13656
    g_string_append_printf (s, "--mirrors %d ", num_mirrors);
 
13657
 
 
13658
  size &= (~511);
 
13659
  g_string_append_printf (s, "--size %" G_GUINT64_FORMAT "b ", size);
 
13660
  if (name != NULL && strlen (name) > 0)
 
13661
    g_string_append_printf (s, "--name \"%s\"", name);
 
13662
 
 
13663
  if (!g_shell_parse_argv (s->str, NULL, &argv, NULL))
 
13664
    {
 
13665
      throw_error (context, ERROR_FAILED, "Unable to parse command line `%s'", s->str);
 
13666
      goto out;
 
13667
    }
 
13668
 
 
13669
  if (!job_new (context,
 
13670
                "LinuxLvm2LVCreate",
 
13671
                TRUE,
 
13672
                NULL,
 
13673
                argv,
 
13674
                NULL,
 
13675
                linux_lvm2_lv_create_completed_cb,
 
13676
                FALSE,
 
13677
                lvm2_lv_create_data_new (context, daemon, group_uuid, name, fstype, fsoptions),
 
13678
                (GDestroyNotify) lvm2_lv_create_data_unref))
 
13679
    {
 
13680
      goto out;
 
13681
    }
 
13682
 
 
13683
 out:
 
13684
  if (s != NULL)
 
13685
    g_string_free (s, FALSE);
 
13686
  g_strfreev (argv);
 
13687
}
 
13688
 
 
13689
gboolean
 
13690
daemon_linux_lvm2_lv_create (Daemon *daemon,
 
13691
                             const gchar *group_uuid,
 
13692
                             const gchar *name,
 
13693
                             guint64 size,
 
13694
                             guint num_stripes,
 
13695
                             guint64 stripe_size,
 
13696
                             guint num_mirrors,
 
13697
                             gchar **options,
 
13698
                             char *fstype,
 
13699
                             char **fsoptions,
 
13700
                             DBusGMethodInvocation *context)
 
13701
{
 
13702
  daemon_local_check_auth (daemon,
 
13703
                           NULL,
 
13704
                           "org.freedesktop.udisks.linux-lvm2",
 
13705
                           "LinuxLvm2LVCreate",
 
13706
                           TRUE,
 
13707
                           daemon_linux_lvm2_lv_create_authorized_cb,
 
13708
                           context,
 
13709
                           9,
 
13710
                           g_strdup (group_uuid),
 
13711
                           g_free,
 
13712
                           g_strdup (name),
 
13713
                           g_free,
 
13714
                           g_memdup (&size, sizeof (guint64)),
 
13715
                           g_free,
 
13716
                           GUINT_TO_POINTER (num_stripes),
 
13717
                           NULL,
 
13718
                           g_memdup (&stripe_size, sizeof (guint64)),
 
13719
                           g_free,
 
13720
                           GUINT_TO_POINTER (num_mirrors),
 
13721
                           NULL,
 
13722
                           g_strdupv (options),
 
13723
                           g_strfreev,
 
13724
                           g_strdup (fstype),
 
13725
                           g_free,
 
13726
                           g_strdupv (fsoptions),
 
13727
                           g_strfreev);
 
13728
 
 
13729
  return TRUE;
 
13730
}
 
13731
 
 
13732
/*--------------------------------------------------------------------------------------------------------------*/
 
13733
 
 
13734
static void
 
13735
linux_lvm2_vg_add_pv_completed_cb (DBusGMethodInvocation *context,
 
13736
                                     Device *device,
 
13737
                                     gboolean job_was_cancelled,
 
13738
                                     int status,
 
13739
                                     const char *stderr,
 
13740
                                     const char *stdout,
 
13741
                                     gpointer user_data)
 
13742
{
 
13743
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
13744
    {
 
13745
      dbus_g_method_return (context);
 
13746
    }
 
13747
  else
 
13748
    {
 
13749
      if (job_was_cancelled)
 
13750
        {
 
13751
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
13752
        }
 
13753
      else
 
13754
        {
 
13755
          throw_error (context,
 
13756
                       ERROR_FAILED,
 
13757
                       "Error adding PV for LVM2 Volume Group: vgextend exited with exit code %d: %s",
 
13758
                       WEXITSTATUS (status),
 
13759
                       stderr);
 
13760
        }
 
13761
    }
 
13762
}
 
13763
 
 
13764
static void
 
13765
daemon_linux_lvm2_vg_add_pv_authorized_cb (Daemon *daemon,
 
13766
                                             Device *device,
 
13767
                                             DBusGMethodInvocation *context,
 
13768
                                             const gchar *action_id,
 
13769
                                             guint num_user_data,
 
13770
                                             gpointer *user_data_elements)
 
13771
{
 
13772
  const gchar *uuid = user_data_elements[0];
 
13773
  const gchar *physical_volume = user_data_elements[1];
 
13774
  /* TODO: use options: gchar **options = user_data_elements[2]; */
 
13775
  const gchar *vg_name;
 
13776
  guint n;
 
13777
  gchar *argv[10];
 
13778
  Device *pv;
 
13779
  GError *error;
 
13780
 
 
13781
  /* Unfortunately vgchange does not (yet - file a bug) accept UUIDs - so find the VG name for this
 
13782
   * UUID by looking at PVs
 
13783
   */
 
13784
 
 
13785
  vg_name = find_lvm2_vg_name_for_uuid (daemon, uuid);
 
13786
  if (vg_name == NULL)
 
13787
    {
 
13788
      throw_error (context, ERROR_FAILED, "Cannot find VG with UUID `%s'", uuid);
 
13789
      goto out;
 
13790
    }
 
13791
 
 
13792
  pv = daemon_local_find_by_object_path (daemon, physical_volume);
 
13793
  if (pv == NULL)
 
13794
    {
 
13795
      throw_error (context, ERROR_FAILED, "physical volume doesn't exist");
 
13796
      goto out;
 
13797
    }
 
13798
 
 
13799
  error = NULL;
 
13800
  if (device_local_is_busy (pv, TRUE, TRUE, &error))
 
13801
    {
 
13802
      dbus_g_method_return_error (context, error);
 
13803
      g_error_free (error);
 
13804
      goto out;
 
13805
    }
 
13806
 
 
13807
 
 
13808
  n = 0;
 
13809
  argv[n++] = "vgextend";
 
13810
  argv[n++] = (gchar *) vg_name;
 
13811
  argv[n++] = (gchar *) pv->priv->device_file;
 
13812
  argv[n++] = NULL;
 
13813
 
 
13814
  if (!job_new (context, "LinuxLvm2VGAddPV", TRUE, NULL, argv, NULL, linux_lvm2_vg_add_pv_completed_cb, FALSE, NULL, NULL))
 
13815
    {
 
13816
      goto out;
 
13817
    }
 
13818
 
 
13819
 out:
 
13820
  ;
 
13821
}
 
13822
 
 
13823
gboolean
 
13824
daemon_linux_lvm2_vg_add_pv (Daemon *daemon,
 
13825
                             const gchar *uuid,
 
13826
                             const gchar *object_path,
 
13827
                             gchar **options,
 
13828
                             DBusGMethodInvocation *context)
 
13829
{
 
13830
  daemon_local_check_auth (daemon,
 
13831
                           NULL,
 
13832
                           "org.freedesktop.udisks.linux-lvm2",
 
13833
                           "LinuxLvm2VGAddPV",
 
13834
                           TRUE,
 
13835
                           daemon_linux_lvm2_vg_add_pv_authorized_cb,
 
13836
                           context,
 
13837
                           3,
 
13838
                           g_strdup (uuid),
 
13839
                           g_free,
 
13840
                           g_strdup (object_path),
 
13841
                           g_free,
 
13842
                           g_strdupv (options),
 
13843
                           g_strfreev);
 
13844
 
 
13845
  return TRUE;
 
13846
}
 
13847
 
 
13848
/*--------------------------------------------------------------------------------------------------------------*/
 
13849
 
 
13850
static void
 
13851
linux_lvm2_vg_remove_pv_completed_cb (DBusGMethodInvocation *context,
 
13852
                                      Device *device,
 
13853
                                      gboolean job_was_cancelled,
 
13854
                                      int status,
 
13855
                                      const char *stderr,
 
13856
                                      const char *stdout,
 
13857
                                      gpointer user_data)
 
13858
{
 
13859
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
 
13860
    {
 
13861
      dbus_g_method_return (context);
 
13862
    }
 
13863
  else
 
13864
    {
 
13865
      if (job_was_cancelled)
 
13866
        {
 
13867
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
 
13868
        }
 
13869
      else
 
13870
        {
 
13871
          throw_error (context,
 
13872
                       ERROR_FAILED,
 
13873
                       "Error removing PV for LVM2 Volume Group: vgreduce exited with exit code %d: %s",
 
13874
                       WEXITSTATUS (status),
 
13875
                       stderr);
 
13876
        }
 
13877
    }
 
13878
}
 
13879
 
 
13880
static void
 
13881
daemon_linux_lvm2_vg_remove_pv_authorized_cb (Daemon *daemon,
 
13882
                                              Device *device,
 
13883
                                              DBusGMethodInvocation *context,
 
13884
                                              const gchar *action_id,
 
13885
                                              guint num_user_data,
 
13886
                                              gpointer *user_data_elements)
 
13887
{
 
13888
  const gchar *vg_uuid = user_data_elements[0];
 
13889
  const gchar *pv_uuid = user_data_elements[1];
 
13890
  /* TODO: use options: gchar **options = user_data_elements[2]; */
 
13891
  const gchar *vg_name;
 
13892
  guint n;
 
13893
  gchar *argv[10];
 
13894
  Device *pv;
 
13895
  GError *error;
 
13896
  GList *devices;
 
13897
  GList *l;
 
13898
 
 
13899
  /* Unfortunately vgchange does not (yet - file a bug) accept UUIDs - so find the VG name for this
 
13900
   * UUID by looking at PVs
 
13901
   */
 
13902
  pv = NULL;
 
13903
 
 
13904
  vg_name = find_lvm2_vg_name_for_uuid (daemon, vg_uuid);
 
13905
  if (vg_name == NULL)
 
13906
    {
 
13907
      throw_error (context, ERROR_FAILED, "Cannot find VG with UUID `%s'", vg_uuid);
 
13908
      goto out;
 
13909
    }
 
13910
 
 
13911
  devices = daemon_local_get_all_devices (daemon);
 
13912
  for (l = devices; l != NULL; l = l->next)
 
13913
    {
 
13914
      Device *d = DEVICE (l->data);
 
13915
 
 
13916
      if (d->priv->device_is_linux_lvm2_pv && g_strcmp0 (d->priv->linux_lvm2_pv_uuid, pv_uuid) == 0)
 
13917
        {
 
13918
          pv = d;
 
13919
          break;
 
13920
        }
 
13921
    }
 
13922
 
 
13923
  if (pv == NULL)
 
13924
    {
 
13925
      throw_error (context, ERROR_FAILED, "Cannot find PV with UUID `%s'", pv_uuid);
 
13926
      goto out;
 
13927
    }
 
13928
 
 
13929
  error = NULL;
 
13930
  if (device_local_is_busy (pv, TRUE, TRUE, &error))
 
13931
    {
 
13932
      dbus_g_method_return_error (context, error);
 
13933
      g_error_free (error);
 
13934
      goto out;
 
13935
    }
 
13936
 
 
13937
  n = 0;
 
13938
  argv[n++] = "vgreduce";
 
13939
  argv[n++] = (gchar *) vg_name;
 
13940
  argv[n++] = (gchar *) pv->priv->device_file;
 
13941
  argv[n++] = NULL;
 
13942
 
 
13943
  if (!job_new (context, "LinuxLvm2VGRemovePV", TRUE, NULL, argv, NULL, linux_lvm2_vg_remove_pv_completed_cb, FALSE, NULL, NULL))
 
13944
    {
 
13945
      goto out;
 
13946
    }
 
13947
 
 
13948
 out:
 
13949
  ;
 
13950
}
 
13951
 
 
13952
gboolean
 
13953
daemon_linux_lvm2_vg_remove_pv (Daemon *daemon,
 
13954
                                const gchar *vg_uuid,
 
13955
                                const gchar *pv_uuid,
 
13956
                                gchar **options,
 
13957
                                DBusGMethodInvocation *context)
 
13958
{
 
13959
  daemon_local_check_auth (daemon,
 
13960
                           NULL,
 
13961
                           "org.freedesktop.udisks.linux-lvm2",
 
13962
                           "LinuxLvm2VGRemovePV",
 
13963
                           TRUE,
 
13964
                           daemon_linux_lvm2_vg_remove_pv_authorized_cb,
 
13965
                           context,
 
13966
                           3,
 
13967
                           g_strdup (vg_uuid),
 
13968
                           g_free,
 
13969
                           g_strdup (pv_uuid),
 
13970
                           g_free,
 
13971
                           g_strdupv (options),
 
13972
                           g_strfreev);
 
13973
 
 
13974
  return TRUE;
 
13975
}
 
13976
 
 
13977
/*--------------------------------------------------------------------------------------------------------------*/
 
13978