static void
update_block (StoragedLinuxBlockObject       *block_object,
              StoragedLinuxVolumeGroupObject *group_object,
              GHashTable                     *new_lvs,
              GHashTable                     *new_pvs)
{
    StoragedBlock *block;
    GVariant *pv_info;

    block = storaged_object_peek_block (STORAGED_OBJECT (block_object));
    if (block == NULL)
        return;

    // XXX - move this elsewhere?
    {
        StoragedLinuxDevice *device;
        StoragedLinuxLogicalVolumeObject *lv_object;
        const gchar *block_vg_name;
        const gchar *block_lv_name;

        device = storaged_linux_block_object_get_device (block_object);
        if (device)
        {
            block_vg_name = g_udev_device_get_property (device->udev_device, "DM_VG_NAME");
            block_lv_name = g_udev_device_get_property (device->udev_device, "DM_LV_NAME");

            if (g_strcmp0 (block_vg_name, storaged_linux_volume_group_object_get_name (group_object)) == 0
                    && (lv_object = g_hash_table_lookup (new_lvs, block_lv_name)))
            {
                block_object_update_lvm_iface (block_object, g_dbus_object_get_object_path (G_DBUS_OBJECT (lv_object)));
            }
        }
    }

    pv_info = g_hash_table_lookup (new_pvs, storaged_block_get_device (block));
    if (!pv_info)
    {
        const gchar *const *symlinks;
        int i;
        symlinks = storaged_block_get_symlinks (block);
        for (i = 0; symlinks[i]; i++)
        {
            pv_info = g_hash_table_lookup (new_pvs, symlinks[i]);
            if (pv_info)
                break;
        }
    }

    if (pv_info)
    {
        storaged_linux_block_object_update_lvm_pv (block_object, group_object, pv_info);
    }
    else
    {
        StoragedPhysicalVolume *pv = storaged_object_peek_physical_volume (STORAGED_OBJECT (block_object));
        if (pv && g_strcmp0 (storaged_physical_volume_get_volume_group (pv),
                             g_dbus_object_get_object_path (G_DBUS_OBJECT (group_object))) == 0)
            storaged_linux_block_object_update_lvm_pv (block_object, NULL, NULL);
    }
}
Ejemplo n.º 2
0
static StoragedObject *
lookup_object_for_block (StoragedClient  *client,
                         dev_t            block_device)
{
  StoragedObject *ret;
  GList *objects;
  GList *l;

  ret = NULL;

  objects = g_dbus_object_manager_get_objects (storaged_client_get_object_manager (client));
  for (l = objects; l != NULL; l = l->next)
    {
      StoragedObject *object = STORAGED_OBJECT (l->data);
      StoragedBlock *block;

      block = storaged_object_peek_block (object);
      if (block != NULL)
        {
          if (block_device == storaged_block_get_device_number (block))
            {
              ret = g_object_ref (object);
              goto out;
            }
        }
    }

 out:
  g_list_foreach (objects, (GFunc) g_object_unref, NULL);
  g_list_free (objects);

  return ret;
}
Ejemplo n.º 3
0
static StoragedObject *
wait_for_volume_group_object (StoragedDaemon *daemon,
                              gpointer        user_data)
{
  const gchar *name = user_data;

  return STORAGED_OBJECT (storaged_daemon_util_lvm2_find_volume_group_object (daemon, name));
}
static gboolean
handle_set_label (StoragedFilesystemBTRFS  *fs_btrfs,
                  GDBusMethodInvocation    *invocation,
                  const gchar              *arg_label,
                  GVariant                 *arg_options)
{
  StoragedLinuxFilesystemBTRFS *l_fs_btrfs = STORAGED_LINUX_FILESYSTEM_BTRFS (fs_btrfs);
  StoragedLinuxBlockObject *object = NULL;
  GError *error = NULL;
  gchar *dev_file = NULL;
  gchar *label = NULL;

  object = storaged_daemon_util_dup_object (l_fs_btrfs, &error);
  if (! object)
    {
      g_dbus_method_invocation_take_error (invocation, error);
      goto out;
    }

  /* Policy check. */
  STORAGED_DAEMON_CHECK_AUTHORIZATION (storaged_linux_filesystem_btrfs_get_daemon (l_fs_btrfs),
                                       STORAGED_OBJECT (object),
                                       btrfs_policy_action_id,
                                       arg_options,
                                       N_("Authentication is required to change label for BTRFS volume"),
                                       invocation);

  /* Allow any arbitrary label. */
  label = g_strdup (arg_label);

  /* Get the device filename (eg.: /dev/sda1) */
  dev_file = storaged_linux_block_object_get_device_file (object);
  if (! dev_file)
    {
      g_dbus_method_invocation_take_error (invocation, error);
      goto out;
    }

  /* Change the label. */
  if (! bd_btrfs_change_label (dev_file, label, &error))
    {
      g_dbus_method_invocation_take_error (invocation, error);
      goto out;
    }

  /* Complete DBus call. */
  storaged_filesystem_btrfs_complete_set_label (fs_btrfs,
                                                invocation);
out:
  g_clear_object (&object);
  g_free ((gpointer) dev_file);
  g_free ((gpointer) label);
  return TRUE;
}
Ejemplo n.º 5
0
static gboolean
dummy_loop_object_process_uevent (StoragedModuleObject  *module_object,
                                  const gchar           *action,
                                  StoragedLinuxDevice   *device)
{
  DummyLoopObject *object;
  GList *link;

  g_return_val_if_fail (DUMMY_IS_LOOP_OBJECT (module_object), FALSE);
  g_return_val_if_fail (device == NULL || STORAGED_IS_LINUX_DEVICE (device), FALSE);

  if (! dummy_loop_object_should_include_device (device))
    return FALSE;

  object = DUMMY_LOOP_OBJECT (module_object);

  link = NULL;
  if (device != NULL)
    link = find_link_for_sysfs_path (object, g_udev_device_get_sysfs_path (device->udev_device));
  if (g_strcmp0 (action, "remove") == 0)
    {
      if (link != NULL)
        {
          g_object_unref (STORAGED_LINUX_DEVICE (link->data));
          object->devices = g_list_delete_link (object->devices, link);
        }
      else
        {
          storaged_warning ("Object doesn't have device with sysfs path %s on remove event",
                            g_udev_device_get_sysfs_path (device->udev_device));
        }
    }
  else
    {
      if (link != NULL)
        {
          g_object_unref (STORAGED_LINUX_DEVICE (link->data));
          link->data = g_object_ref (device);
        }
      else
        {
          if (device != NULL)
            {
              object->devices = g_list_append (object->devices, g_object_ref (device));
              g_object_notify (G_OBJECT (object), "device");
            }
        }
    }

  update_iface (STORAGED_OBJECT (object), action, linux_loop_check, linux_loop_connect, linux_loop_update,
                DUMMY_TYPE_LINUX_LOOP, &object->iface_loop);

  return TRUE;
}
static void
update_progress_for_device (StoragedDaemon *daemon,
                            const gchar    *operation,
                            const gchar    *dev,
                            double          progress)
{
    GDBusObjectManager *object_manager;
    GList *objects, *l;

    object_manager = G_DBUS_OBJECT_MANAGER (storaged_daemon_get_object_manager (daemon));
    objects = g_dbus_object_manager_get_objects (object_manager);

    for (l = objects; l; l = l->next)
    {
        StoragedObject *object = STORAGED_OBJECT (l->data);
        StoragedJob *job;
        const gchar *const *job_objects;
        int i;

        job = storaged_object_peek_job (object);
        if (job == NULL)
            continue;

        if (g_strcmp0 (storaged_job_get_operation (job), operation) != 0)
            continue;

        job_objects = storaged_job_get_objects (job);
        for (i = 0; job_objects[i]; i++)
        {
            StoragedBlock *block = STORAGED_BLOCK (g_dbus_object_manager_get_interface (object_manager,
                                                   job_objects[i],
                                                   "org.storaged.Storaged.Block"));

            if (block)
            {
                const gchar *const *symlinks;
                int j;
                if (g_strcmp0 (storaged_block_get_device (block), dev) == 0)
                    goto found;
                symlinks = storaged_block_get_symlinks (block);
                for (j = 0; symlinks[j]; j++)
                    if (g_strcmp0 (symlinks[j], dev) == 0)
                        goto found;

                continue;
found:
                storaged_job_set_progress (job, progress);
                storaged_job_set_progress_valid (job, TRUE);
            }
        }

    }
    g_list_free_full (objects, g_object_unref);
}
static gboolean
handle_resize (StoragedFilesystemBTRFS  *fs_btrfs,
               GDBusMethodInvocation    *invocation,
               guint64                   arg_size,
               GVariant                 *arg_options)
{
  StoragedLinuxFilesystemBTRFS *l_fs_btrfs = STORAGED_LINUX_FILESYSTEM_BTRFS (fs_btrfs);
  StoragedLinuxBlockObject *object = NULL;
  GError *error = NULL;
  gchar *mount_point = NULL;

  object = storaged_daemon_util_dup_object (l_fs_btrfs, &error);
  if (! object)
    {
      g_dbus_method_invocation_take_error (invocation, error);
      goto out;
    }

  /* Policy check. */
  STORAGED_DAEMON_CHECK_AUTHORIZATION (storaged_linux_filesystem_btrfs_get_daemon (l_fs_btrfs),
                                       STORAGED_OBJECT (object),
                                       btrfs_policy_action_id,
                                       arg_options,
                                       N_("Authentication is required to resize the volume"),
                                       invocation);

  /* Get the mount point for this volume. */
  mount_point = storaged_filesystem_btrfs_get_first_mount_point (fs_btrfs, &error);
  if (! mount_point)
    {
      g_dbus_method_invocation_take_error (invocation, error);
      goto out;
    }

  /* Resize the volume. */
  if (! bd_btrfs_resize (mount_point, arg_size, &error))
    {
      g_dbus_method_invocation_take_error (invocation, error);
      goto out;
    }

  /* Complete DBus call. */
  storaged_filesystem_btrfs_complete_resize (fs_btrfs,
                                             invocation);

out:
  g_clear_object (&object);
  g_free ((gpointer) mount_point);

  /* Indicate that we handled the method invocation */
  return TRUE;
}
static gboolean
have_partition_in_range (StoragedPartitionTable     *table,
                         StoragedObject             *object,
                         guint64                     start,
                         guint64                     end,
                         gboolean                    ignore_container)
{
  gboolean ret = FALSE;
  StoragedDaemon *daemon = NULL;
  GDBusObjectManager *object_manager = NULL;
  const gchar *table_object_path;
  GList *objects = NULL, *l;

  daemon = storaged_linux_block_object_get_daemon (STORAGED_LINUX_BLOCK_OBJECT (object));
  object_manager = G_DBUS_OBJECT_MANAGER (storaged_daemon_get_object_manager (daemon));

  table_object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));

  objects = g_dbus_object_manager_get_objects (object_manager);
  for (l = objects; l != NULL; l = l->next)
    {
      StoragedObject *i_object = STORAGED_OBJECT (l->data);
      StoragedPartition *i_partition = NULL;

      i_partition = storaged_object_get_partition (i_object);

      if (i_partition == NULL)
        goto cont;

      if (g_strcmp0 (storaged_partition_get_table (i_partition), table_object_path) != 0)
        goto cont;

      if (ignore_container && storaged_partition_get_is_container (i_partition))
        goto cont;

      if (!ranges_overlap (start, end - start,
                           storaged_partition_get_offset (i_partition), storaged_partition_get_size (i_partition)))
        goto cont;

      ret = TRUE;
      g_clear_object (&i_partition);
      goto out;

    cont:
      g_clear_object (&i_partition);
    }

 out:
  g_list_foreach (objects, (GFunc) g_object_unref, NULL);
  g_list_free (objects);
  return ret;
}
Ejemplo n.º 9
0
/**
 * storaged_linux_block_object_uevent:
 * @object: A #StoragedLinuxBlockObject.
 * @action: Uevent action or %NULL
 * @device: A new #StoragedLinuxDevice device object or %NULL if the device hasn't changed.
 *
 * Updates all information on interfaces on @object.
 */
void
storaged_linux_block_object_uevent (StoragedLinuxBlockObject *object,
                                    const gchar              *action,
                                    StoragedLinuxDevice      *device)
{
    StoragedModuleManager *module_manager;
    GHashTableIter iter;
    gpointer key;
    ModuleInterfaceEntry *entry;

    g_return_if_fail (STORAGED_IS_LINUX_BLOCK_OBJECT (object));
    g_return_if_fail (device == NULL || STORAGED_IS_LINUX_DEVICE (device));

    if (device != NULL)
    {
        g_object_unref (object->device);
        object->device = g_object_ref (device);
        g_object_notify (G_OBJECT (object), "device");
    }

    update_iface (STORAGED_OBJECT (object), action, block_device_check, block_device_connect, block_device_update,
                  STORAGED_TYPE_LINUX_BLOCK, &object->iface_block_device);
    update_iface (STORAGED_OBJECT (object), action, filesystem_check, filesystem_connect, filesystem_update,
                  STORAGED_TYPE_LINUX_FILESYSTEM, &object->iface_filesystem);
    update_iface (STORAGED_OBJECT (object), action, swapspace_check, swapspace_connect, swapspace_update,
                  STORAGED_TYPE_LINUX_SWAPSPACE, &object->iface_swapspace);
    update_iface (STORAGED_OBJECT (object), action, encrypted_check, encrypted_connect, encrypted_update,
                  STORAGED_TYPE_LINUX_ENCRYPTED, &object->iface_encrypted);
    update_iface (STORAGED_OBJECT (object), action, loop_check, loop_connect, loop_update,
                  STORAGED_TYPE_LINUX_LOOP, &object->iface_loop);
    update_iface (STORAGED_OBJECT (object), action, partition_table_check, partition_table_connect, partition_table_update,
                  STORAGED_TYPE_LINUX_PARTITION_TABLE, &object->iface_partition_table);
    update_iface (STORAGED_OBJECT (object), action, partition_check, partition_connect, partition_update,
                  STORAGED_TYPE_LINUX_PARTITION, &object->iface_partition);

    /* Attach interfaces from modules */
    module_manager = storaged_daemon_get_module_manager (object->daemon);
    if (storaged_module_manager_get_modules_available (module_manager))
    {
        ensure_module_ifaces (object, module_manager);
        g_hash_table_iter_init (&iter, object->module_ifaces);
        while (g_hash_table_iter_next (&iter, &key, (gpointer *) &entry))
        {
            update_iface (STORAGED_OBJECT (object), action, entry->has_func, entry->connect_func, entry->update_func,
                          (GType) key, &entry->interface);
        }
    }
}
Ejemplo n.º 10
0
/**
 * storaged_linux_drive_object_get_block:
 * @object: A #StoragedLinuxDriveObject.
 * @get_hw: If the drive is multipath, set to %TRUE to get a path device instead of the multipath device.
 *
 * Gets a #StoragedLinuxBlockObject representing a block device associated with @object.
 *
 * Returns: A #StoragedLinuxBlockObject or %NULL. The returned object
 * must be freed with g_object_unref().
 */
StoragedLinuxBlockObject *
storaged_linux_drive_object_get_block (StoragedLinuxDriveObject   *object,
                                       gboolean                    get_hw)
{
    GDBusObjectManagerServer *object_manager;
    StoragedLinuxBlockObject *ret;
    GList *objects;
    GList *l;

    /* TODO: actually look at @get_hw */

    ret = NULL;

    object_manager = storaged_daemon_get_object_manager (object->daemon);
    objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (object_manager));
    for (l = objects; l != NULL; l = l->next)
    {
        GDBusObjectSkeleton *iter_object = G_DBUS_OBJECT_SKELETON (l->data);
        StoragedBlock *block;
        StoragedLinuxDevice *device;
        gboolean is_disk;

        if (!STORAGED_IS_LINUX_BLOCK_OBJECT (iter_object))
            continue;

        device = storaged_linux_block_object_get_device (STORAGED_LINUX_BLOCK_OBJECT (iter_object));
        is_disk = (g_strcmp0 (g_udev_device_get_devtype (device->udev_device), "disk") == 0);
        g_object_unref (device);

        if (!is_disk)
            continue;

        block = storaged_object_peek_block (STORAGED_OBJECT (iter_object));
        if (g_strcmp0 (storaged_block_get_drive (block),
                       g_dbus_object_get_object_path (G_DBUS_OBJECT (object))) == 0)
        {
            ret = g_object_ref (iter_object);
            goto out;
        }
    }

out:
    g_list_foreach (objects, (GFunc) g_object_unref, NULL);
    g_list_free (objects);
    return ret;
}
static void
block_object_update_lvm_iface (StoragedLinuxBlockObject *object,
                               const gchar *lv_obj_path)
{
    StoragedBlockLVM2 *iface_block_lvm2;

    iface_block_lvm2 = storaged_object_peek_block_lvm2 (STORAGED_OBJECT (object));

    if (iface_block_lvm2 == NULL)
    {
        iface_block_lvm2 = storaged_linux_block_lvm2_new ();
        g_dbus_object_skeleton_add_interface (G_DBUS_OBJECT_SKELETON (object),
                                              G_DBUS_INTERFACE_SKELETON (iface_block_lvm2));
        g_object_unref (iface_block_lvm2);
    }

    storaged_linux_block_lvm2_update (STORAGED_LINUX_BLOCK_LVM2 (iface_block_lvm2), object);
    storaged_block_lvm2_set_logical_volume (iface_block_lvm2, lv_obj_path);
}
Ejemplo n.º 12
0
static gboolean
is_block_unlocked (GList *objects, const gchar *crypto_object_path)
{
    gboolean ret = FALSE;
    GList *l;
    for (l = objects; l != NULL; l = l->next)
    {
        StoragedObject *object = STORAGED_OBJECT (l->data);
        StoragedBlock *block;
        block = storaged_object_peek_block (object);
        if (block != NULL)
        {
            if (g_strcmp0 (storaged_block_get_crypto_backing_device (block), crypto_object_path) == 0)
            {
                ret = TRUE;
                goto out;
            }
        }
    }
out:
    return ret;
}
static StoragedObject *
wait_for_partition (StoragedDaemon *daemon,
                    gpointer        user_data)
{
  WaitForPartitionData *data = user_data;
  StoragedObject *ret = NULL;
  GList *objects, *l;

  objects = storaged_daemon_get_objects (daemon);
  for (l = objects; l != NULL; l = l->next)
    {
      StoragedObject *object = STORAGED_OBJECT (l->data);
      StoragedPartition *partition = storaged_object_get_partition (object);
      if (partition != NULL)
        {
          if (g_strcmp0 (storaged_partition_get_table (partition),
                         g_dbus_object_get_object_path (G_DBUS_OBJECT (data->partition_table_object))) == 0)
            {
              guint64 offset = storaged_partition_get_offset (partition);
              guint64 size = storaged_partition_get_size (partition);

              if (data->pos_to_wait_for >= offset && data->pos_to_wait_for < offset + size)
                {
                  if (!(storaged_partition_get_is_container (partition) && data->ignore_container))
                    {
                      g_object_unref (partition);
                      ret = g_object_ref (object);
                      goto out;
                    }
                }
            }
          g_object_unref (partition);
        }
    }

 out:
  g_list_free_full (objects, g_object_unref);
  return ret;
}
Ejemplo n.º 14
0
/**
 * storaged_linux_drive_object_uevent:
 * @object: A #StoragedLinuxDriveObject.
 * @action: Uevent action or %NULL
 * @device: A #StoragedLinuxDevice device object or %NULL if the device hasn't changed.
 *
 * Updates all information on interfaces on @drive.
 */
void
storaged_linux_drive_object_uevent (StoragedLinuxDriveObject *object,
                                    const gchar              *action,
                                    StoragedLinuxDevice      *device)
{
    GList *link;
    gboolean conf_changed;
    StoragedModuleManager *module_manager;
    GHashTableIter iter;
    gpointer key;
    ModuleInterfaceEntry *entry;

    g_return_if_fail (STORAGED_IS_LINUX_DRIVE_OBJECT (object));
    g_return_if_fail (device == NULL || STORAGED_IS_LINUX_DEVICE (device));

    link = NULL;
    if (device != NULL)
        link = find_link_for_sysfs_path (object, g_udev_device_get_sysfs_path (device->udev_device));
    if (g_strcmp0 (action, "remove") == 0)
    {
        if (link != NULL)
        {
            g_object_unref (STORAGED_LINUX_DEVICE (link->data));
            object->devices = g_list_delete_link (object->devices, link);
        }
        else
        {
            storaged_warning ("Drive doesn't have device with sysfs path %s on remove event",
                              device ? g_udev_device_get_sysfs_path (device->udev_device) : "(null device)");
        }
    }
    else
    {
        if (link != NULL)
        {
            g_object_unref (STORAGED_LINUX_DEVICE (link->data));
            link->data = g_object_ref (device);
        }
        else
        {
            if (device != NULL)
                object->devices = g_list_append (object->devices, g_object_ref (device));
        }
    }

    conf_changed = FALSE;
    conf_changed |= update_iface (STORAGED_OBJECT (object), action, drive_check, drive_connect, drive_update,
                                  STORAGED_TYPE_LINUX_DRIVE, &object->iface_drive);
    conf_changed |= update_iface (STORAGED_OBJECT (object), action, drive_ata_check, drive_ata_connect, drive_ata_update,
                                  STORAGED_TYPE_LINUX_DRIVE_ATA, &object->iface_drive_ata);

    /* Attach interfaces from modules */
    module_manager = storaged_daemon_get_module_manager (object->daemon);
    if (storaged_module_manager_get_modules_available (module_manager))
    {
        ensure_module_ifaces (object, module_manager);
        g_hash_table_iter_init (&iter, object->module_ifaces);
        while (g_hash_table_iter_next (&iter, &key, (gpointer *) &entry))
        {
            conf_changed |= update_iface (STORAGED_OBJECT (object), action, entry->has_func, entry->connect_func, entry->update_func,
                                          (GType) key, &entry->interface);
        }
    }

    if (conf_changed)
        apply_configuration (object);
}
Ejemplo n.º 15
0
/**
 * storaged_linux_drive_object_is_not_in_use:
 * @object: A #StoragedLinuxDriveObject.
 * @cancellable: (allow-none): A #GCancellable or %NULL.
 * @error: A #GError or %NULL.
 *
 * Checks if the drive represented by @object is in use and sets
 * @error if so.
 *
 * Returns: %TRUE if @object is not is use, %FALSE if @error is set.
 */
gboolean
storaged_linux_drive_object_is_not_in_use (StoragedLinuxDriveObject   *object,
        GCancellable               *cancellable,
        GError                    **error)
{
    GDBusObjectManagerServer *object_manager;
    const gchar *drive_object_path;
    gboolean ret = TRUE;
    GList *objects = NULL;
    GList *l;

    g_return_val_if_fail (STORAGED_IS_LINUX_DRIVE_OBJECT (object), FALSE);
    g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
    g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

    drive_object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));

    object_manager = storaged_daemon_get_object_manager (object->daemon);
    objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (object_manager));

    /* Visit all block devices related to the drive... */
    for (l = objects; l != NULL; l = l->next)
    {
        GDBusObjectSkeleton *iter_object = G_DBUS_OBJECT_SKELETON (l->data);
        StoragedBlock *block;
        StoragedFilesystem *filesystem;

        if (!STORAGED_IS_LINUX_BLOCK_OBJECT (iter_object))
            continue;

        block = storaged_object_peek_block (STORAGED_OBJECT (iter_object));
        filesystem = storaged_object_peek_filesystem (STORAGED_OBJECT (iter_object));

        if (g_strcmp0 (storaged_block_get_drive (block), drive_object_path) != 0)
            continue;

        /* bail if block device is mounted */
        if (filesystem != NULL)
        {
            if (g_strv_length ((gchar **) storaged_filesystem_get_mount_points (filesystem)) > 0)
            {
                g_set_error (error,
                             STORAGED_ERROR,
                             STORAGED_ERROR_DEVICE_BUSY,
                             "Device %s is mounted",
                             storaged_block_get_preferred_device (block));
                ret = FALSE;
                goto out;
            }
        }

        /* bail if block device is unlocked (LUKS) */
        if (is_block_unlocked (objects, g_dbus_object_get_object_path (G_DBUS_OBJECT (iter_object))))
        {
            g_set_error (error,
                         STORAGED_ERROR,
                         STORAGED_ERROR_DEVICE_BUSY,
                         "Encrypted device %s is unlocked",
                         storaged_block_get_preferred_device (block));
            ret = FALSE;
            goto out;
        }
    }

out:
    g_list_free_full (objects, g_object_unref);
    return ret;
}
static gboolean
btrfs_subvolume_perform_action (StoragedFilesystemBTRFS  *fs_btrfs,
                                GDBusMethodInvocation    *invocation,
                                btrfs_subvolume_func      subvolume_action,
                                const gchar              *arg_name,
                                GVariant                 *arg_options,
                                const gchar              *polkit_message)
{
  StoragedLinuxFilesystemBTRFS *l_fs_btrfs = STORAGED_LINUX_FILESYSTEM_BTRFS (fs_btrfs);
  StoragedLinuxBlockObject *object = NULL;
  GError *error = NULL;
  gchar *name = NULL;
  gchar *mount_point = NULL;

  object = storaged_daemon_util_dup_object (l_fs_btrfs, &error);
  if (! object)
    {
      g_dbus_method_invocation_take_error (invocation, error);
      goto out;
    }

  /* Policy check. */
  STORAGED_DAEMON_CHECK_AUTHORIZATION (storaged_linux_filesystem_btrfs_get_daemon (l_fs_btrfs),
                                       STORAGED_OBJECT (object),
                                       btrfs_policy_action_id,
                                       arg_options,
                                       N_(polkit_message),
                                       invocation);

  /* Do we have a valid subvolume name? */
  if (! *arg_name)
    {
      g_dbus_method_invocation_return_error (invocation,
                                             STORAGED_ERROR,
                                             STORAGED_ERROR_FAILED,
                                             "Invalid subvolume name");
      goto out;
    }
  name = g_strdup (arg_name);

  /* Get the mount point for this volume. */
  mount_point = storaged_filesystem_btrfs_get_first_mount_point (fs_btrfs, &error);
  if (! mount_point)
    {
      g_dbus_method_invocation_take_error (invocation, error);
      goto out;
    }

  /* Add/remove the subvolume. */
  if (! subvolume_action (mount_point, name, &error))
    {
      g_dbus_method_invocation_take_error (invocation, error);
      goto out;
    }

  /* Complete DBus call. */
  storaged_filesystem_btrfs_complete_set_label (fs_btrfs,
                                                invocation);

out:
  /* Release the resources */
  g_clear_object (&object);
  g_free ((gpointer) name);
  g_free ((gpointer) mount_point);

  /* Indicate that we handled the method invocation */
  return TRUE;
}
static gboolean
btrfs_device_perform_action (StoragedFilesystemBTRFS  *fs_btrfs,
                             GDBusMethodInvocation    *invocation,
                             btrfs_device_func         device_action,
                             const gchar              *arg_device,
                             GVariant                 *arg_options)
{
  StoragedLinuxFilesystemBTRFS *l_fs_btrfs = STORAGED_LINUX_FILESYSTEM_BTRFS (fs_btrfs);
  StoragedLinuxBlockObject *object = NULL;
  GError *error = NULL;
  gchar *mount_point = NULL;
  gchar *device = NULL;

  object = storaged_daemon_util_dup_object (fs_btrfs, &error);
  if (! object)
    {
      g_dbus_method_invocation_take_error (invocation, error);
      goto out;
    }

  /* Policy check. */
  STORAGED_DAEMON_CHECK_AUTHORIZATION (storaged_linux_filesystem_btrfs_get_daemon (l_fs_btrfs),
                                       STORAGED_OBJECT (object),
                                       btrfs_policy_action_id,
                                       arg_options,
                                       N_("Authentication is required to add "
                                          "the device to the volume"),
                                       invocation);

  /* Get the mount point for this volume. */
  mount_point = storaged_filesystem_btrfs_get_first_mount_point (fs_btrfs, &error);
  if (! mount_point)
    {
      g_dbus_method_invocation_take_error (invocation, error);
      goto out;
    }

  device = g_strdup (arg_device);

  /* Add/remove the device to/from the volume. */
  if (! device_action (mount_point, device, &error))
    {
      g_dbus_method_invocation_take_error (invocation, error);
      goto out;
    }

  /* Update the interface. */
  storaged_linux_filesystem_btrfs_update (l_fs_btrfs, object);

  /* Complete DBus call. */
  storaged_filesystem_btrfs_complete_add_device (fs_btrfs, invocation);

out:
  /* Release the resources */
  g_clear_object (&object);
  g_free ((gpointer) mount_point);
  g_free ((gpointer) device);

  /* Indicate that we handled the method invocation. */
  return TRUE;
}
static gboolean
handle_create_snapshot(StoragedFilesystemBTRFS  *fs_btrfs,
                       GDBusMethodInvocation    *invocation,
                       const gchar              *arg_source,
                       const gchar              *arg_dest,
                       gboolean                  arg_ro,
                       GVariant                 *arg_options)
{
  StoragedLinuxFilesystemBTRFS *l_fs_btrfs = STORAGED_LINUX_FILESYSTEM_BTRFS (fs_btrfs);
  StoragedLinuxBlockObject *object = NULL;
  GError *error = NULL;
  gchar *source = NULL;
  gchar *dest = NULL;
  gchar *mount_point = NULL;

  object = storaged_daemon_util_dup_object (fs_btrfs, &error);
  if (! object)
    {
      g_dbus_method_invocation_take_error (invocation, error);
      goto out;
    }

  /* Policy check. */
  STORAGED_DAEMON_CHECK_AUTHORIZATION (storaged_linux_filesystem_btrfs_get_daemon (l_fs_btrfs),
                                       STORAGED_OBJECT (object),
                                       btrfs_policy_action_id,
                                       arg_options,
                                       N_("Authentication is required to create a new snapshot"),
                                       invocation);

  /* Prefix source and destination directories with mount point; so that user
   * doesn't need to always type in a full path.
   */
  mount_point = storaged_filesystem_btrfs_get_first_mount_point (fs_btrfs, &error);
  if (! mount_point)
    {
      g_dbus_method_invocation_take_error (invocation, error);
      goto out;
    }
  source = g_build_path (G_DIR_SEPARATOR_S, mount_point, arg_source, NULL);
  dest = g_build_path (G_DIR_SEPARATOR_S, mount_point, arg_dest, NULL);

  /* Create the snapshot. */
  if (! bd_btrfs_create_snapshot (source, dest, arg_ro, &error))
    {
      g_dbus_method_invocation_take_error (invocation, error);
      goto out;
    }

  /* Complete DBus call. */
  storaged_filesystem_btrfs_complete_create_snapshot (fs_btrfs,
                                                      invocation);

out:
  /* Release the resources */
  g_clear_object (&object);
  g_free ((gpointer) source);
  g_free ((gpointer) dest);
  g_free ((gpointer) mount_point);

  /* Indicate that we handled the method invocation */
  return TRUE;
}
static gboolean
handle_get_subvolumes (StoragedFilesystemBTRFS  *fs_btrfs,
                       GDBusMethodInvocation    *invocation,
                       gboolean                  arg_snapshots_only,
                       GVariant                 *arg_options)
{
  StoragedLinuxFilesystemBTRFS *l_fs_btrfs = STORAGED_LINUX_FILESYSTEM_BTRFS (fs_btrfs);
  StoragedLinuxBlockObject *object = NULL;
  BDBtrfsSubvolumeInfo **subvolumes_info = NULL;
  GVariant *subvolumes = NULL;
  GError *error = NULL;
  gchar *mount_point = NULL;
  gint subvolumes_cnt = 0;

  object = storaged_daemon_util_dup_object (fs_btrfs, &error);
  if (! object)
    {
      g_dbus_method_invocation_take_error (invocation, error);
      goto out;
    }

  /* Policy check. */
  STORAGED_DAEMON_CHECK_AUTHORIZATION (storaged_linux_filesystem_btrfs_get_daemon (l_fs_btrfs),
                                       STORAGED_OBJECT (object),
                                       btrfs_policy_action_id,
                                       arg_options,
                                       N_("Authentication is required to change label "
                                          "for BTRFS volume"),
                                       invocation);

  /* Get the mount point for this volume. */
  mount_point = storaged_filesystem_btrfs_get_first_mount_point (fs_btrfs, &error);
  if (! mount_point)
    {
      g_dbus_method_invocation_take_error (invocation, error);
      goto out;
    }

  /* Get subvolume infos. */
  subvolumes_info = bd_btrfs_list_subvolumes (mount_point,
                                              arg_snapshots_only,
                                              &error);

  if (! subvolumes_info && error)
    {
      g_dbus_method_invocation_take_error (invocation, error);
      goto out;
    }

  subvolumes = btrfs_subvolumes_to_gvariant (subvolumes_info, &subvolumes_cnt);

  /* Complete DBus call. */
  storaged_filesystem_btrfs_complete_get_subvolumes (fs_btrfs,
                                                     invocation,
                                                     subvolumes,
                                                     subvolumes_cnt);

out:
  /* Release the resources */
  g_clear_object (&object);
  btrfs_free_subvolumes_info (subvolumes_info);
  g_free ((gpointer) mount_point);

  /* Indicate that we handled the method invocation */
  return TRUE;
}