1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 *
3 * Copyright (C) 2007-2010 David Zeuthen <zeuthen@gmail.com>
4 * Copyright (C) 2013 Marius Vollmer <marius.vollmer@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 */
21
22 #include "config.h"
23 #include <glib/gi18n-lib.h>
24
25 #include <sys/types.h>
26 #include <pwd.h>
27 #include <grp.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <mntent.h>
32
33 #include <glib/gstdio.h>
34
35 #include <blockdev/fs.h>
36 #include <blockdev/lvm.h>
37
38 #include <src/udiskslogging.h>
39 #include <src/udiskslinuxprovider.h>
40 #include <src/udisksdaemon.h>
41 #include <src/udisksstate.h>
42 #include <src/udisksdaemonutil.h>
43 #include <src/udiskslinuxdevice.h>
44 #include <src/udiskslinuxblock.h>
45 #include <src/udiskslinuxblockobject.h>
46
47 #include "udiskslinuxvolumegroup.h"
48 #include "udiskslinuxvolumegroupobject.h"
49 #include "udiskslinuxlogicalvolume.h"
50 #include "udiskslinuxlogicalvolumeobject.h"
51
52 #include "udiskslvm2daemonutil.h"
53 #include "jobhelpers.h"
54
55 /**
56 * SECTION:udiskslinuxvolume_group
57 * @title: UDisksLinuxVolumeGroup
58 * @short_description: Linux implementation of #UDisksVolumeGroup
59 *
60 * This type provides an implementation of the #UDisksVolumeGroup interface
61 * on Linux.
62 */
63
64 typedef struct _UDisksLinuxVolumeGroupClass UDisksLinuxVolumeGroupClass;
65
66 /**
67 * UDisksLinuxVolumeGroup:
68 *
69 * The #UDisksLinuxVolumeGroup structure contains only private data and should
70 * only be accessed using the provided API.
71 */
72 struct _UDisksLinuxVolumeGroup
73 {
74 UDisksVolumeGroupSkeleton parent_instance;
75 };
76
77 struct _UDisksLinuxVolumeGroupClass
78 {
79 UDisksVolumeGroupSkeletonClass parent_class;
80 };
81
82 static void volume_group_iface_init (UDisksVolumeGroupIface *iface);
83
84 G_DEFINE_TYPE_WITH_CODE (UDisksLinuxVolumeGroup, udisks_linux_volume_group, UDISKS_TYPE_VOLUME_GROUP_SKELETON,
85 G_IMPLEMENT_INTERFACE (UDISKS_TYPE_VOLUME_GROUP, volume_group_iface_init));
86
87 /* ---------------------------------------------------------------------------------------------------- */
88
89 static void
udisks_linux_volume_group_finalize(GObject * object)90 udisks_linux_volume_group_finalize (GObject *object)
91 {
92 if (G_OBJECT_CLASS (udisks_linux_volume_group_parent_class)->finalize != NULL)
93 G_OBJECT_CLASS (udisks_linux_volume_group_parent_class)->finalize (object);
94 }
95
96 static void
udisks_linux_volume_group_init(UDisksLinuxVolumeGroup * volume_group)97 udisks_linux_volume_group_init (UDisksLinuxVolumeGroup *volume_group)
98 {
99 g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (volume_group),
100 G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
101 }
102
103 static void
udisks_linux_volume_group_class_init(UDisksLinuxVolumeGroupClass * klass)104 udisks_linux_volume_group_class_init (UDisksLinuxVolumeGroupClass *klass)
105 {
106 GObjectClass *gobject_class;
107
108 gobject_class = G_OBJECT_CLASS (klass);
109 gobject_class->finalize = udisks_linux_volume_group_finalize;
110 }
111
112 /**
113 * udisks_linux_volume_group_new:
114 *
115 * Creates a new #UDisksLinuxVolumeGroup instance.
116 *
117 * Returns: A new #UDisksLinuxVolumeGroup. Free with g_object_unref().
118 */
119 UDisksVolumeGroup *
udisks_linux_volume_group_new(void)120 udisks_linux_volume_group_new (void)
121 {
122 return UDISKS_VOLUME_GROUP (g_object_new (UDISKS_TYPE_LINUX_VOLUME_GROUP,
123 NULL));
124 }
125
126 /**
127 * udisks_linux_volume_group_update:
128 * @volume_group: A #UDisksLinuxVolumeGroup.
129 * @object: The enclosing #UDisksLinuxVolumeGroupObject instance.
130 *
131 * Updates the interface.
132 */
133 void
udisks_linux_volume_group_update(UDisksLinuxVolumeGroup * volume_group,BDLVMVGdata * vg_info,gboolean * needs_polling_ret)134 udisks_linux_volume_group_update (UDisksLinuxVolumeGroup *volume_group,
135 BDLVMVGdata *vg_info,
136 gboolean *needs_polling_ret)
137 {
138 UDisksVolumeGroup *iface = UDISKS_VOLUME_GROUP (volume_group);
139
140 udisks_volume_group_set_name (iface, vg_info->name);
141 udisks_volume_group_set_uuid (iface, vg_info->uuid);
142 udisks_volume_group_set_size (iface, vg_info->size);
143 udisks_volume_group_set_free_size (iface, vg_info->free);
144 udisks_volume_group_set_extent_size (iface, vg_info->extent_size);
145
146 g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (iface));
147 }
148
149 /* ---------------------------------------------------------------------------------------------------- */
150
151 static gboolean
handle_poll(UDisksVolumeGroup * _group,GDBusMethodInvocation * invocation)152 handle_poll (UDisksVolumeGroup *_group,
153 GDBusMethodInvocation *invocation)
154 {
155 UDisksLinuxVolumeGroup *group = UDISKS_LINUX_VOLUME_GROUP (_group);
156 UDisksLinuxVolumeGroupObject *object = NULL;
157 GError *error = NULL;
158
159 object = udisks_daemon_util_dup_object (group, &error);
160 if (object == NULL)
161 {
162 g_dbus_method_invocation_take_error (invocation, error);
163 goto out;
164 }
165
166 udisks_linux_volume_group_object_poll (object);
167
168 udisks_volume_group_complete_poll (_group, invocation);
169
170 out:
171 g_clear_object (&object);
172 return TRUE;
173 }
174
175 /* ---------------------------------------------------------------------------------------------------- */
176
177 /* transfer-full */
178 GList *
udisks_linux_volume_group_get_logical_volumes(UDisksVolumeGroup * group,UDisksDaemon * daemon)179 udisks_linux_volume_group_get_logical_volumes (UDisksVolumeGroup *group,
180 UDisksDaemon *daemon)
181 {
182 GList *ret = NULL;
183 GList *l, *objects = NULL;
184 GDBusObject *object;
185 UDisksLogicalVolume *volume;
186
187 object = g_dbus_interface_get_object (G_DBUS_INTERFACE (group));
188 if (object == NULL)
189 goto out;
190
191 objects = udisks_daemon_get_objects (daemon);
192 for (l = objects; l != NULL; l = l->next)
193 {
194 volume = udisks_object_peek_logical_volume (UDISKS_OBJECT (l->data));
195 if (volume &&
196 g_strcmp0 (udisks_logical_volume_get_volume_group (volume),
197 g_dbus_object_get_object_path (object)) == 0)
198 ret = g_list_append (ret, g_object_ref (volume));
199 }
200
201 out:
202 g_list_free_full (objects, g_object_unref);
203 return ret;
204 }
205
206 /* ---------------------------------------------------------------------------------------------------- */
207
208 static gboolean
teardown_volume_group(UDisksVolumeGroup * group,UDisksDaemon * daemon,GDBusMethodInvocation * invocation,GVariant * options,GError ** error)209 teardown_volume_group (UDisksVolumeGroup *group,
210 UDisksDaemon *daemon,
211 GDBusMethodInvocation *invocation,
212 GVariant *options,
213 GError **error)
214 {
215 GList *volumes;
216 GList *l;
217 UDisksLogicalVolume *volume;
218
219 volumes = udisks_linux_volume_group_get_logical_volumes (group, daemon);
220 for (l = volumes; l; l = l->next)
221 {
222 volume = UDISKS_LOGICAL_VOLUME (l->data);
223 if (g_strcmp0 (udisks_logical_volume_get_type_ (volume), "pool") != 0)
224 {
225 if (!udisks_linux_logical_volume_teardown_block (volume,
226 daemon,
227 invocation,
228 options,
229 error))
230 {
231 g_list_free_full (volumes, g_object_unref);
232 return FALSE;
233 }
234 }
235 }
236 g_list_free_full (volumes, g_object_unref);
237
238 return TRUE;
239 }
240
241 static gboolean
handle_delete(UDisksVolumeGroup * _group,GDBusMethodInvocation * invocation,gboolean arg_wipe,GVariant * arg_options)242 handle_delete (UDisksVolumeGroup *_group,
243 GDBusMethodInvocation *invocation,
244 gboolean arg_wipe,
245 GVariant *arg_options)
246 {
247 GError *error = NULL;
248 UDisksLinuxVolumeGroup *group = UDISKS_LINUX_VOLUME_GROUP (_group);
249 UDisksLinuxVolumeGroupObject *object = NULL;
250 UDisksLinuxModuleLVM2 *module;
251 UDisksDaemon *daemon;
252 uid_t caller_uid;
253 gboolean teardown_flag = FALSE;
254 GList *objects_to_wipe = NULL;
255 GList *l;
256 VGJobData data;
257
258 g_variant_lookup (arg_options, "tear-down", "b", &teardown_flag);
259
260 object = udisks_daemon_util_dup_object (group, &error);
261 if (object == NULL)
262 {
263 g_dbus_method_invocation_take_error (invocation, error);
264 goto out;
265 }
266
267 module = udisks_linux_volume_group_object_get_module (object);
268 daemon = udisks_module_get_daemon (UDISKS_MODULE (module));
269
270 /* Find physical volumes to wipe. */
271 if (arg_wipe)
272 {
273 GList *objects = udisks_daemon_get_objects (daemon);
274 for (l = objects; l; l = l->next)
275 {
276 UDisksPhysicalVolume *physical_volume;
277 physical_volume = udisks_object_peek_physical_volume (UDISKS_OBJECT (l->data));
278 if (physical_volume
279 && g_strcmp0 (udisks_physical_volume_get_volume_group (physical_volume),
280 g_dbus_object_get_object_path (G_DBUS_OBJECT (object))) == 0)
281 objects_to_wipe = g_list_append (objects_to_wipe, g_object_ref (l->data));
282 }
283 g_list_free_full (objects, g_object_unref);
284 }
285
286 if (!udisks_daemon_util_get_caller_uid_sync (daemon,
287 invocation,
288 NULL /* GCancellable */,
289 &caller_uid,
290 &error))
291 {
292 g_dbus_method_invocation_return_gerror (invocation, error);
293 g_clear_error (&error);
294 goto out;
295 }
296
297 /* Policy check. */
298 UDISKS_DAEMON_CHECK_AUTHORIZATION (daemon,
299 UDISKS_OBJECT (object),
300 LVM2_POLICY_ACTION_ID,
301 arg_options,
302 N_("Authentication is required to delete a volume group"),
303 invocation);
304
305 if (teardown_flag &&
306 !teardown_volume_group (_group,
307 daemon,
308 invocation,
309 arg_options,
310 &error))
311 {
312 g_dbus_method_invocation_take_error (invocation, error);
313 goto out;
314 }
315
316 data.vg_name = udisks_linux_volume_group_object_get_name (object);
317
318 if (!udisks_daemon_launch_threaded_job_sync (daemon,
319 UDISKS_OBJECT (object),
320 "lvm-vg-delete",
321 caller_uid,
322 vgremove_job_func,
323 &data,
324 NULL, /* user_data_free_func */
325 NULL, /* GCancellable */
326 &error))
327 {
328 g_dbus_method_invocation_return_error (invocation,
329 UDISKS_ERROR,
330 UDISKS_ERROR_FAILED,
331 "Error deleting volume group: %s",
332 error->message);
333 g_clear_error (&error);
334 goto out;
335 }
336
337 for (l = objects_to_wipe; l; l = l->next)
338 {
339 UDisksBlock *block = udisks_object_peek_block (l->data);
340 if (block)
341 udisks_daemon_util_lvm2_wipe_block (daemon, block, NULL);
342 }
343
344 udisks_volume_group_complete_delete (_group, invocation);
345
346 out:
347 g_list_free_full (objects_to_wipe, g_object_unref);
348 g_clear_object (&object);
349 return TRUE;
350 }
351
352 /* ---------------------------------------------------------------------------------------------------- */
353
354 typedef struct
355 {
356 UDisksLinuxModuleLVM2 *module;
357 const gchar *name;
358 } WaitForVolumeGroupObjectData;
359
360 static UDisksObject *
wait_for_volume_group_object(UDisksDaemon * daemon,gpointer user_data)361 wait_for_volume_group_object (UDisksDaemon *daemon,
362 gpointer user_data)
363 {
364 WaitForVolumeGroupObjectData *data = user_data;
365 UDisksLinuxVolumeGroupObject *object;
366
367 object = udisks_linux_module_lvm2_find_volume_group_object (data->module, data->name);
368
369 if (object == NULL)
370 return NULL;
371
372 return g_object_ref (UDISKS_OBJECT (object));
373 }
374
375 static gboolean
handle_rename(UDisksVolumeGroup * _group,GDBusMethodInvocation * invocation,const gchar * new_name,GVariant * options)376 handle_rename (UDisksVolumeGroup *_group,
377 GDBusMethodInvocation *invocation,
378 const gchar *new_name,
379 GVariant *options)
380 {
381 GError *error = NULL;
382 UDisksLinuxVolumeGroup *group = UDISKS_LINUX_VOLUME_GROUP (_group);
383 UDisksLinuxVolumeGroupObject *object = NULL;
384 UDisksLinuxModuleLVM2 *module;
385 UDisksDaemon *daemon;
386 uid_t caller_uid;
387 UDisksObject *group_object = NULL;
388 VGJobData data;
389 WaitForVolumeGroupObjectData wait_data;
390
391 object = udisks_daemon_util_dup_object (group, &error);
392 if (object == NULL)
393 {
394 g_dbus_method_invocation_take_error (invocation, error);
395 goto out;
396 }
397
398 module = udisks_linux_volume_group_object_get_module (object);
399 daemon = udisks_module_get_daemon (UDISKS_MODULE (module));
400
401 if (!udisks_daemon_util_get_caller_uid_sync (daemon,
402 invocation,
403 NULL /* GCancellable */,
404 &caller_uid,
405 &error))
406 {
407 g_dbus_method_invocation_return_gerror (invocation, error);
408 g_clear_error (&error);
409 goto out;
410 }
411
412 /* Policy check. */
413 UDISKS_DAEMON_CHECK_AUTHORIZATION (daemon,
414 UDISKS_OBJECT (object),
415 LVM2_POLICY_ACTION_ID,
416 options,
417 N_("Authentication is required to rename a volume group"),
418 invocation);
419
420 data.vg_name = udisks_linux_volume_group_object_get_name (object);
421 data.new_vg_name = new_name;
422
423 if (!udisks_daemon_launch_threaded_job_sync (daemon,
424 UDISKS_OBJECT (object),
425 "lvm-vg-rename",
426 caller_uid,
427 vgrename_job_func,
428 &data,
429 NULL, /* user_data_free_func */
430 NULL, /* GCancellable */
431 &error))
432 {
433 g_dbus_method_invocation_return_error (invocation,
434 UDISKS_ERROR,
435 UDISKS_ERROR_FAILED,
436 "Error renaming volume group: %s",
437 error->message);
438 g_clear_error (&error);
439 goto out;
440 }
441
442 wait_data.module = module;
443 wait_data.name = new_name;
444 group_object = udisks_daemon_wait_for_object_sync (daemon,
445 wait_for_volume_group_object,
446 &wait_data,
447 NULL,
448 UDISKS_DEFAULT_WAIT_TIMEOUT,
449 &error);
450 if (group_object == NULL)
451 {
452 g_prefix_error (&error,
453 "Error waiting for volume group object for '%s': ",
454 new_name);
455 g_dbus_method_invocation_take_error (invocation, error);
456 goto out;
457 }
458
459 udisks_volume_group_complete_rename (_group,
460 invocation,
461 g_dbus_object_get_object_path (G_DBUS_OBJECT (group_object)));
462 g_clear_object (&group_object);
463
464 out:
465 g_clear_object (&object);
466 return TRUE;
467 }
468
469 /* ---------------------------------------------------------------------------------------------------- */
470
471 static gboolean
handle_add_device(UDisksVolumeGroup * _group,GDBusMethodInvocation * invocation,const gchar * new_member_device_objpath,GVariant * options)472 handle_add_device (UDisksVolumeGroup *_group,
473 GDBusMethodInvocation *invocation,
474 const gchar *new_member_device_objpath,
475 GVariant *options)
476 {
477 UDisksLinuxVolumeGroup *group = UDISKS_LINUX_VOLUME_GROUP (_group);
478 UDisksLinuxModuleLVM2 *module;
479 UDisksDaemon *daemon;
480 UDisksLinuxVolumeGroupObject *object;
481 uid_t caller_uid;
482 GError *error = NULL;
483 UDisksObject *new_member_device_object = NULL;
484 UDisksBlock *new_member_device = NULL;
485 UDisksPhysicalVolume *physical_volume = NULL;
486 VGJobData data;
487
488 object = udisks_daemon_util_dup_object (group, &error);
489 if (object == NULL)
490 {
491 g_dbus_method_invocation_take_error (invocation, error);
492 goto out;
493 }
494
495 module = udisks_linux_volume_group_object_get_module (object);
496 daemon = udisks_module_get_daemon (UDISKS_MODULE (module));
497
498 error = NULL;
499 if (!udisks_daemon_util_get_caller_uid_sync (daemon,
500 invocation,
501 NULL /* GCancellable */,
502 &caller_uid,
503 &error))
504 {
505 g_dbus_method_invocation_return_gerror (invocation, error);
506 g_clear_error (&error);
507 goto out;
508 }
509
510 new_member_device_object = udisks_daemon_find_object (daemon, new_member_device_objpath);
511 if (new_member_device_object == NULL)
512 {
513 g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED,
514 "No device for given object path");
515 goto out;
516 }
517
518 new_member_device = udisks_object_get_block (new_member_device_object);
519 if (new_member_device == NULL)
520 {
521 g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED,
522 "No block interface on given object");
523 goto out;
524 }
525
526 /* Policy check. */
527 UDISKS_DAEMON_CHECK_AUTHORIZATION (daemon,
528 UDISKS_OBJECT (object),
529 LVM2_POLICY_ACTION_ID,
530 options,
531 N_("Authentication is required to add a device to a volume group"),
532 invocation);
533
534 if (!udisks_daemon_util_lvm2_block_is_unused (new_member_device, &error))
535 {
536 g_dbus_method_invocation_take_error (invocation, error);
537 goto out;
538 }
539
540 if (!udisks_daemon_util_lvm2_wipe_block (daemon, new_member_device, &error))
541 {
542 g_dbus_method_invocation_take_error (invocation, error);
543 goto out;
544 }
545
546 physical_volume = udisks_object_peek_physical_volume (new_member_device_object);
547 if (!physical_volume)
548 {
549 PVJobData pv_data;
550 pv_data.path = udisks_block_get_device (new_member_device);
551 if (!udisks_daemon_launch_threaded_job_sync (daemon,
552 UDISKS_OBJECT (object),
553 "lvm-pv-create",
554 caller_uid,
555 pvcreate_job_func,
556 &pv_data,
557 NULL, /* user_data_free_func */
558 NULL, /* GCancellable */
559 &error))
560 {
561 g_dbus_method_invocation_return_error (invocation,
562 UDISKS_ERROR,
563 UDISKS_ERROR_FAILED,
564 "Error creating LVM metadata on %s: %s",
565 pv_data.path,
566 error->message);
567 g_clear_error (&error);
568 goto out;
569 }
570 }
571
572
573 data.vg_name = udisks_linux_volume_group_object_get_name (object);
574 data.pv_path = udisks_block_get_device (new_member_device);
575
576 if (!udisks_daemon_launch_threaded_job_sync (daemon,
577 UDISKS_OBJECT (object),
578 "lvm-vg-add-device",
579 caller_uid,
580 vgextend_job_func,
581 &data,
582 NULL, /* user_data_free_func */
583 NULL, /* GCancellable */
584 &error))
585 {
586 g_dbus_method_invocation_return_error (invocation,
587 UDISKS_ERROR,
588 UDISKS_ERROR_FAILED,
589 "Error adding %s to volume group: %s",
590 data.pv_path,
591 error->message);
592 g_clear_error (&error);
593 goto out;
594 }
595
596 udisks_volume_group_complete_add_device (_group, invocation);
597
598 out:
599 g_clear_object (&new_member_device_object);
600 g_clear_object (&new_member_device);
601 g_clear_object (&object);
602 return TRUE; /* returning TRUE means that we handled the method invocation */
603 }
604
605 /* ---------------------------------------------------------------------------------------------------- */
606 static gboolean
handle_remove_common(UDisksVolumeGroup * _group,GDBusMethodInvocation * invocation,const gchar * member_device_objpath,GVariant * options,gboolean is_remove,gboolean arg_wipe)607 handle_remove_common (UDisksVolumeGroup *_group,
608 GDBusMethodInvocation *invocation,
609 const gchar *member_device_objpath,
610 GVariant *options,
611 gboolean is_remove,
612 gboolean arg_wipe)
613 {
614 UDisksLinuxVolumeGroup *group = UDISKS_LINUX_VOLUME_GROUP (_group);
615 UDisksLinuxModuleLVM2 *module;
616 UDisksDaemon *daemon;
617 UDisksLinuxVolumeGroupObject *object;
618 uid_t caller_uid;
619 GError *error = NULL;
620 UDisksObject *member_device_object = NULL;
621 UDisksBlock *member_device = NULL;
622 VGJobData data;
623 const gchar *authentication_error_msg = NULL;
624 const gchar *job_operation = NULL;
625 UDisksThreadedJobFunc job_func = NULL;
626 gboolean do_wipe = FALSE;
627
628 if (is_remove)
629 {
630 authentication_error_msg = N_("Authentication is required to remove a device from a volume group");
631 job_operation = "lvm-vg-rem-device";
632 job_func = vgreduce_job_func;
633
634 if (arg_wipe)
635 do_wipe = TRUE;
636 }
637 else
638 {
639 authentication_error_msg = N_("Authentication is required to empty a device in a volume group");
640 job_operation = "lvm-vg-empty-device";
641 job_func = pvmove_job_func;
642 }
643
644 object = udisks_daemon_util_dup_object (group, &error);
645 if (object == NULL)
646 {
647 g_dbus_method_invocation_take_error (invocation, error);
648 goto out;
649 }
650
651 module = udisks_linux_volume_group_object_get_module (object);
652 daemon = udisks_module_get_daemon (UDISKS_MODULE (module));
653
654 error = NULL;
655 if (!udisks_daemon_util_get_caller_uid_sync (daemon,
656 invocation,
657 NULL /* GCancellable */,
658 &caller_uid,
659 &error))
660 {
661 g_dbus_method_invocation_return_gerror (invocation, error);
662 g_clear_error (&error);
663 goto out;
664 }
665
666 member_device_object = udisks_daemon_find_object (daemon, member_device_objpath);
667 if (member_device_object == NULL)
668 {
669 g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED,
670 "No device for given object path");
671 goto out;
672 }
673
674 member_device = udisks_object_get_block (member_device_object);
675 if (member_device == NULL)
676 {
677 g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED,
678 "No block interface on given object");
679 goto out;
680 }
681
682 /* Policy check. */
683 UDISKS_DAEMON_CHECK_AUTHORIZATION (daemon,
684 UDISKS_OBJECT (object),
685 LVM2_POLICY_ACTION_ID,
686 options,
687 authentication_error_msg,
688 invocation);
689
690 if (is_remove)
691 data.vg_name = udisks_linux_volume_group_object_get_name (object);
692
693 data.pv_path = udisks_block_get_device (member_device);
694
695 if (!udisks_daemon_launch_threaded_job_sync (daemon,
696 UDISKS_OBJECT (object),
697 job_operation,
698 caller_uid,
699 job_func,
700 &data,
701 NULL, /* user_data_free_func */
702 NULL, /* GCancellable */
703 &error))
704 {
705 g_dbus_method_invocation_return_error (invocation,
706 UDISKS_ERROR,
707 UDISKS_ERROR_FAILED,
708 (is_remove) ? "Error remove %s from volume group: %s" : "Error emptying %s: %s",
709 data.pv_path,
710 error->message);
711 g_clear_error (&error);
712 goto out;
713 }
714
715 if (do_wipe)
716 {
717 if (!udisks_daemon_launch_threaded_job_sync (daemon,
718 UDISKS_OBJECT (object),
719 "pv-format-erase",
720 caller_uid,
721 pvremove_job_func,
722 &data,
723 NULL, /* user_data_free_func */
724 NULL, /* GCancellable */
725 &error))
726 {
727 g_dbus_method_invocation_return_error (invocation,
728 UDISKS_ERROR,
729 UDISKS_ERROR_FAILED,
730 "Error wiping %s after removal from volume group %s: %s",
731 data.pv_path,
732 udisks_linux_volume_group_object_get_name (object),
733 error->message);
734 g_clear_error (&error);
735 goto out;
736 }
737 }
738
739 udisks_volume_group_complete_remove_device (_group, invocation);
740
741 out:
742 g_clear_object (&member_device_object);
743 g_clear_object (&member_device);
744 g_clear_object (&object);
745 return TRUE; /* returning TRUE means that we handled the method invocation */
746 }
747
748
749 static gboolean
handle_remove_device(UDisksVolumeGroup * _group,GDBusMethodInvocation * invocation,const gchar * member_device_objpath,gboolean arg_wipe,GVariant * options)750 handle_remove_device (UDisksVolumeGroup *_group,
751 GDBusMethodInvocation *invocation,
752 const gchar *member_device_objpath,
753 gboolean arg_wipe,
754 GVariant *options)
755 {
756 return handle_remove_common (_group, invocation, member_device_objpath,
757 options, TRUE, arg_wipe);
758 }
759
760 /* ---------------------------------------------------------------------------------------------------- */
761
762 static gboolean
handle_empty_device(UDisksVolumeGroup * _group,GDBusMethodInvocation * invocation,const gchar * member_device_objpath,GVariant * options)763 handle_empty_device (UDisksVolumeGroup *_group,
764 GDBusMethodInvocation *invocation,
765 const gchar *member_device_objpath,
766 GVariant *options)
767 {
768 return handle_remove_common (_group, invocation, member_device_objpath,
769 options, FALSE, FALSE);
770 }
771
772 /* ---------------------------------------------------------------------------------------------------- */
773
774 struct WaitData {
775 UDisksLinuxVolumeGroupObject *group_object;
776 const gchar *name;
777 };
778
779 static UDisksObject *
wait_for_logical_volume_object(UDisksDaemon * daemon,gpointer user_data)780 wait_for_logical_volume_object (UDisksDaemon *daemon,
781 gpointer user_data)
782 {
783 struct WaitData *data = user_data;
784 UDisksLinuxLogicalVolumeObject *object;
785
786 object = udisks_linux_volume_group_object_find_logical_volume_object (data->group_object, data->name);
787 if (object == NULL)
788 return NULL;
789
790 return g_object_ref (UDISKS_OBJECT (object));
791 }
792
793 static const gchar *
wait_for_logical_volume_path(UDisksLinuxVolumeGroupObject * group_object,const gchar * name,GError ** error)794 wait_for_logical_volume_path (UDisksLinuxVolumeGroupObject *group_object,
795 const gchar *name,
796 GError **error)
797 {
798 struct WaitData data;
799 UDisksLinuxModuleLVM2 *module;
800 UDisksDaemon *daemon;
801 UDisksObject *volume_object;
802 const gchar *object_path;
803
804 data.group_object = group_object;
805 data.name = name;
806 module = udisks_linux_volume_group_object_get_module (group_object);
807 daemon = udisks_module_get_daemon (UDISKS_MODULE (module));
808 volume_object = udisks_daemon_wait_for_object_sync (daemon,
809 wait_for_logical_volume_object,
810 &data,
811 NULL,
812 UDISKS_DEFAULT_WAIT_TIMEOUT,
813 error);
814 if (volume_object == NULL)
815 return NULL;
816
817 object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (volume_object));
818 g_object_unref (volume_object);
819
820 return object_path;
821 }
822
823 /* ---------------------------------------------------------------------------------------------------- */
824
825 enum VolumeType { VOL_PLAIN, VOL_THIN_POOL, VOL_THIN_VOLUME, VOL_VDO_VOLUME };
826 typedef void (*VolumeCompletionFunc) (UDisksVolumeGroup *object,
827 GDBusMethodInvocation *invocation,
828 const gchar *result);
829
830 static gboolean
handle_create_volume(UDisksVolumeGroup * _group,GDBusMethodInvocation * invocation,const gchar * arg_name,guint64 arg_size,GVariant * options,enum VolumeType vol_creation_type,const gchar * arg_pool,guint64 arg_virtual_size,guint64 arg_index_memory,gboolean arg_compression,gboolean arg_deduplication,const gchar * arg_write_policy)831 handle_create_volume (UDisksVolumeGroup *_group,
832 GDBusMethodInvocation *invocation,
833 const gchar *arg_name,
834 guint64 arg_size,
835 GVariant *options,
836 enum VolumeType vol_creation_type,
837 const gchar *arg_pool,
838 guint64 arg_virtual_size,
839 guint64 arg_index_memory,
840 gboolean arg_compression,
841 gboolean arg_deduplication,
842 const gchar *arg_write_policy)
843 {
844 GError *error = NULL;
845 UDisksLinuxVolumeGroup *group = UDISKS_LINUX_VOLUME_GROUP (_group);
846 UDisksLinuxVolumeGroupObject *object = NULL;
847 UDisksLinuxModuleLVM2 *module;
848 UDisksDaemon *daemon;
849 uid_t caller_uid;
850 const gchar *lv_objpath;
851 LVJobData data = {0};
852 UDisksLinuxLogicalVolumeObject *pool_object = NULL;
853 const gchar *auth_error_msg = NULL;
854 UDisksThreadedJobFunc create_function = NULL;
855 VolumeCompletionFunc completion_function = NULL;
856
857 if (VOL_PLAIN == vol_creation_type)
858 {
859 auth_error_msg = N_("Authentication is required to create a logical volume");
860 create_function = lvcreate_job_func;
861 completion_function = udisks_volume_group_complete_create_plain_volume;
862 }
863 else if (VOL_THIN_VOLUME == vol_creation_type)
864 {
865 auth_error_msg = N_("Authentication is required to create a thin volume");
866 create_function = lvcreate_thin_job_func;
867 completion_function = udisks_volume_group_complete_create_thin_volume;
868 }
869 else if (VOL_THIN_POOL == vol_creation_type)
870 {
871 auth_error_msg = N_("Authentication is required to create a thin pool volume");
872 create_function = lvcreate_thin_pool_job_func;
873 completion_function = udisks_volume_group_complete_create_thin_pool_volume;
874 }
875 else if (VOL_VDO_VOLUME == vol_creation_type)
876 {
877 auth_error_msg = N_("Authentication is required to create a VDO volume");
878 create_function = lvcreate_vdo_job_func;
879 completion_function = udisks_volume_group_complete_create_vdo_volume;
880 }
881
882 object = udisks_daemon_util_dup_object (group, &error);
883 if (object == NULL)
884 {
885 g_dbus_method_invocation_take_error (invocation, error);
886 goto out;
887 }
888
889 module = udisks_linux_volume_group_object_get_module (object);
890 daemon = udisks_module_get_daemon (UDISKS_MODULE (module));
891 if (!udisks_daemon_util_get_caller_uid_sync (daemon,
892 invocation,
893 NULL /* GCancellable */,
894 &caller_uid,
895 &error))
896 {
897 g_dbus_method_invocation_return_gerror (invocation, error);
898 g_clear_error (&error);
899 goto out;
900 }
901
902 /* Policy check. */
903 UDISKS_DAEMON_CHECK_AUTHORIZATION (daemon,
904 UDISKS_OBJECT (object),
905 LVM2_POLICY_ACTION_ID,
906 options,
907 auth_error_msg,
908 invocation);
909
910 data.vg_name = udisks_linux_volume_group_object_get_name (object);
911 data.new_lv_name = arg_name;
912 data.new_lv_size = arg_size;
913
914 if (VOL_THIN_POOL == vol_creation_type)
915 data.extent_size = udisks_volume_group_get_extent_size (UDISKS_VOLUME_GROUP (group));
916
917 if (VOL_THIN_VOLUME == vol_creation_type)
918 {
919 pool_object = UDISKS_LINUX_LOGICAL_VOLUME_OBJECT (udisks_daemon_find_object (daemon, arg_pool));
920 if (pool_object == NULL || !UDISKS_IS_LINUX_LOGICAL_VOLUME_OBJECT (pool_object))
921 {
922 g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED,
923 "Not a logical volume");
924 goto out;
925 }
926 data.pool_name = udisks_linux_logical_volume_object_get_name (pool_object);
927 }
928
929 if (VOL_VDO_VOLUME == vol_creation_type)
930 {
931 data.pool_name = arg_pool;
932 data.virtual_size = arg_virtual_size;
933 data.index_memory = arg_index_memory;
934 data.compression = arg_compression;
935 data.deduplication = arg_deduplication;
936 data.write_policy = arg_write_policy;
937 }
938
939 if (!udisks_daemon_launch_threaded_job_sync (daemon,
940 UDISKS_OBJECT (object),
941 "lvm-vg-create-volume",
942 caller_uid,
943 create_function,
944 &data,
945 NULL, /* user_data_free_func */
946 NULL, /* GCancellable */
947 &error))
948 {
949 g_dbus_method_invocation_return_error (invocation,
950 UDISKS_ERROR,
951 UDISKS_ERROR_FAILED,
952 "Error creating volume: %s",
953 error->message);
954 g_clear_error (&error);
955 goto out;
956 }
957
958 lv_objpath = wait_for_logical_volume_path (object, arg_name, &error);
959 if (lv_objpath == NULL)
960 {
961 g_prefix_error (&error,
962 "Error waiting for logical volume object for '%s': ",
963 arg_name);
964 g_dbus_method_invocation_take_error (invocation, error);
965 goto out;
966 }
967
968 completion_function (_group, invocation, lv_objpath);
969
970 out:
971 g_clear_object (&pool_object);
972 g_clear_object (&object);
973 return TRUE;
974 }
975
976 static gboolean
handle_create_plain_volume(UDisksVolumeGroup * _group,GDBusMethodInvocation * invocation,const gchar * arg_name,guint64 arg_size,GVariant * options)977 handle_create_plain_volume (UDisksVolumeGroup *_group,
978 GDBusMethodInvocation *invocation,
979 const gchar *arg_name,
980 guint64 arg_size,
981 GVariant *options)
982 {
983 return handle_create_volume(_group, invocation, arg_name, arg_size, options,
984 VOL_PLAIN, NULL, 0, 0, FALSE, FALSE, NULL);
985 }
986
987 /* ---------------------------------------------------------------------------------------------------- */
988
989 static gboolean
handle_create_thin_pool_volume(UDisksVolumeGroup * _group,GDBusMethodInvocation * invocation,const gchar * arg_name,guint64 arg_size,GVariant * options)990 handle_create_thin_pool_volume (UDisksVolumeGroup *_group,
991 GDBusMethodInvocation *invocation,
992 const gchar *arg_name,
993 guint64 arg_size,
994 GVariant *options)
995 {
996 return handle_create_volume(_group, invocation, arg_name, arg_size, options,
997 VOL_THIN_POOL, NULL, 0, 0, FALSE, FALSE, NULL);
998 }
999
1000 /* ---------------------------------------------------------------------------------------------------- */
1001
1002 static gboolean
handle_create_thin_volume(UDisksVolumeGroup * _group,GDBusMethodInvocation * invocation,const gchar * arg_name,guint64 arg_size,const gchar * arg_pool,GVariant * options)1003 handle_create_thin_volume (UDisksVolumeGroup *_group,
1004 GDBusMethodInvocation *invocation,
1005 const gchar *arg_name,
1006 guint64 arg_size,
1007 const gchar *arg_pool,
1008 GVariant *options)
1009 {
1010 return handle_create_volume(_group, invocation, arg_name, arg_size, options,
1011 VOL_THIN_VOLUME, arg_pool, 0, 0, FALSE, FALSE, NULL);
1012 }
1013
1014 static gboolean
handle_create_vdo_volume(UDisksVolumeGroup * _group,GDBusMethodInvocation * invocation,const gchar * arg_name,const gchar * arg_pool,guint64 arg_size,guint64 arg_virtual_size,guint64 arg_index_memory,gboolean arg_compression,gboolean arg_deduplication,const gchar * arg_write_policy,GVariant * options)1015 handle_create_vdo_volume (UDisksVolumeGroup *_group,
1016 GDBusMethodInvocation *invocation,
1017 const gchar *arg_name,
1018 const gchar *arg_pool,
1019 guint64 arg_size,
1020 guint64 arg_virtual_size,
1021 guint64 arg_index_memory,
1022 gboolean arg_compression,
1023 gboolean arg_deduplication,
1024 const gchar *arg_write_policy,
1025 GVariant *options)
1026 {
1027 return handle_create_volume (_group, invocation, arg_name, arg_size, options,
1028 VOL_VDO_VOLUME, arg_pool, arg_virtual_size, arg_index_memory,
1029 arg_compression, arg_deduplication, arg_write_policy);
1030 }
1031
1032 /* ---------------------------------------------------------------------------------------------------- */
1033
1034 static void
volume_group_iface_init(UDisksVolumeGroupIface * iface)1035 volume_group_iface_init (UDisksVolumeGroupIface *iface)
1036 {
1037 iface->handle_poll = handle_poll;
1038
1039 iface->handle_delete = handle_delete;
1040 iface->handle_rename = handle_rename;
1041
1042 iface->handle_add_device = handle_add_device;
1043 iface->handle_remove_device = handle_remove_device;
1044 iface->handle_empty_device = handle_empty_device;
1045
1046 iface->handle_create_plain_volume = handle_create_plain_volume;
1047 iface->handle_create_thin_pool_volume = handle_create_thin_pool_volume;
1048 iface->handle_create_thin_volume = handle_create_thin_volume;
1049
1050 iface->handle_create_vdo_volume = handle_create_vdo_volume;
1051 }
1052