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
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;
}
void
storaged_linux_volume_group_object_destroy (StoragedLinuxVolumeGroupObject *object)
{
    GHashTableIter volume_iter;
    gpointer key, value;

    g_hash_table_iter_init (&volume_iter, object->logical_volumes);
    while (g_hash_table_iter_next (&volume_iter, &key, &value))
    {
        StoragedLinuxLogicalVolumeObject *volume = value;
        g_dbus_object_manager_server_unexport (storaged_daemon_get_object_manager (object->daemon),
                                               g_dbus_object_get_object_path (G_DBUS_OBJECT (volume)));
    }
}
/**
 * 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;
}
/**
 * storaged_linux_drive_object_get_siblings:
 * @object: A #StoragedLinuxDriveObject.
 *
 * Gets the siblings for @object, if any.
 *
 * Returns: (transfer full) (element-type StoragedLinuxDriveObject): A list of #StoragedLinuxDriveObject
 *   instances. The returned list should be freed with g_list_free() after each element has been
 *   freed with g_object_unref().
 */
GList *
storaged_linux_drive_object_get_siblings (StoragedLinuxDriveObject *object)
{
    GDBusObjectManagerServer *object_manager;
    GList *ret = NULL;
    GList *objects = NULL;
    GList *l;
    gchar *sibling_id = NULL;

    if (object->iface_drive == NULL)
        goto out;

    sibling_id = storaged_drive_dup_sibling_id (object->iface_drive);
    if (sibling_id == NULL || strlen (sibling_id) == 0)
        goto out;

    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);
        StoragedLinuxDriveObject *iter_linux_drive_object;

        if (!STORAGED_IS_LINUX_DRIVE_OBJECT (iter_object))
            continue;

        iter_linux_drive_object = STORAGED_LINUX_DRIVE_OBJECT (iter_object);
        if (iter_linux_drive_object->iface_drive != NULL &&
                g_strcmp0 (storaged_drive_get_sibling_id (iter_linux_drive_object->iface_drive), sibling_id) == 0)
        {
            ret = g_list_prepend (ret, g_object_ref (iter_object));
        }
    }

out:
    ret = g_list_reverse (ret);
    g_list_foreach (objects, (GFunc) g_object_unref, NULL);
    g_list_free (objects);
    g_free (sibling_id);
    return ret;
}
/**
 * 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 void
update_with_variant (GPid pid,
                     GVariant *info,
                     GError *error,
                     gpointer user_data)
{
    StoragedLinuxVolumeGroupObject *object = user_data;
    StoragedDaemon *daemon;
    GDBusObjectManagerServer *manager;
    GVariantIter *iter;
    GHashTableIter volume_iter;
    gpointer key, value;
    GHashTable *new_lvs;
    GHashTable *new_pvs;
    GList *objects, *l;
    gboolean needs_polling = FALSE;

    daemon = storaged_linux_volume_group_object_get_daemon (object);
    manager = storaged_daemon_get_object_manager (daemon);

    if (error)
    {
        storaged_warning ("Failed to update LVM volume group %s: %s",
                          storaged_linux_volume_group_object_get_name (object),
                          error->message);
        g_object_unref (object);
        return;
    }

    storaged_linux_volume_group_update (STORAGED_LINUX_VOLUME_GROUP (object->iface_volume_group), info, &needs_polling);

    if (!g_dbus_object_manager_server_is_exported (manager, G_DBUS_OBJECT_SKELETON (object)))
        g_dbus_object_manager_server_export_uniquely (manager, G_DBUS_OBJECT_SKELETON (object));

    new_lvs = g_hash_table_new (g_str_hash, g_str_equal);

    if (g_variant_lookup (info, "lvs", "aa{sv}", &iter))
    {
        GVariant *lv_info = NULL;
        while (g_variant_iter_loop (iter, "@a{sv}", &lv_info))
        {
            const gchar *name;
            StoragedLinuxLogicalVolumeObject *volume;

            g_variant_lookup (lv_info, "name", "&s", &name);

            update_operations (daemon, name, lv_info, &needs_polling);

            if (lv_is_pvmove_volume (name))
                needs_polling = TRUE;

            if (storaged_daemon_util_lvm2_name_is_reserved (name))
                continue;

            volume = g_hash_table_lookup (object->logical_volumes, name);
            if (volume == NULL)
            {
                volume = storaged_linux_logical_volume_object_new (daemon, object, name);
                storaged_linux_logical_volume_object_update (volume, lv_info, &needs_polling);
                storaged_linux_logical_volume_object_update_etctabs (volume);
                g_dbus_object_manager_server_export_uniquely (manager, G_DBUS_OBJECT_SKELETON (volume));
                g_hash_table_insert (object->logical_volumes, g_strdup (name), g_object_ref (volume));
            }
            else
                storaged_linux_logical_volume_object_update (volume, lv_info, &needs_polling);

            g_hash_table_insert (new_lvs, (gchar *)name, volume);
        }
        g_variant_iter_free (iter);
    }

    g_hash_table_iter_init (&volume_iter, object->logical_volumes);
    while (g_hash_table_iter_next (&volume_iter, &key, &value))
    {
        const gchar *name = key;
        StoragedLinuxLogicalVolumeObject *volume = value;

        if (!g_hash_table_contains (new_lvs, name))
        {
            g_dbus_object_manager_server_unexport (manager,
                                                   g_dbus_object_get_object_path (G_DBUS_OBJECT (volume)));
            g_hash_table_iter_remove (&volume_iter);

            g_object_unref (G_OBJECT (volume));
        }
    }

    storaged_volume_group_set_needs_polling (STORAGED_VOLUME_GROUP (object->iface_volume_group),
            needs_polling);

    /* Update block objects. */

    new_pvs = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)g_variant_unref);
    if (g_variant_lookup (info, "pvs", "aa{sv}", &iter))
    {
        const gchar *name;
        GVariant *pv_info;
        while (g_variant_iter_next (iter, "@a{sv}", &pv_info))
        {
            if (g_variant_lookup (pv_info, "device", "&s", &name))
                g_hash_table_insert (new_pvs, (gchar *)name, pv_info);
            else
                g_variant_unref (pv_info);
        }
    }

    objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (manager));
    for (l = objects; l != NULL; l = l->next)
    {
        if (STORAGED_IS_LINUX_BLOCK_OBJECT (l->data))
            update_block (STORAGED_LINUX_BLOCK_OBJECT (l->data), object, new_lvs, new_pvs);
    }
    g_list_free_full (objects, g_object_unref);

    g_hash_table_destroy (new_lvs);
    g_hash_table_destroy (new_pvs);

    g_object_unref (object);
}