コード例 #1
0
ファイル: storagevolumegroup.c プロジェクト: finid/cockpit
static gboolean
handle_create_thin_volume (CockpitStorageVolumeGroup *object,
                           GDBusMethodInvocation *invocation,
                           const gchar *arg_name,
                           guint64 arg_size,
                           const gchar *arg_pool)
{
  StorageVolumeGroup *group = STORAGE_VOLUME_GROUP(object);
  GError *error = NULL;
  gs_free gchar *result = NULL;
  const gchar *pool_path = "/";

  if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
    return TRUE;

  StorageProvider *provider = storage_object_get_provider (group->object);
  Daemon *daemon = storage_provider_get_daemon (provider);
  GDBusObjectManagerServer *object_manager_server = daemon_get_object_manager (daemon);
  GDBusObjectManager *object_manager = G_DBUS_OBJECT_MANAGER (object_manager_server);

  StorageObject *pool_object =
    STORAGE_OBJECT (g_dbus_object_manager_get_object (object_manager, arg_pool));
  LvmLogicalVolume *lvm_pool_lvol = storage_object_get_lvm_logical_volume (pool_object);

  if (lvm_pool_lvol)
    pool_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (lvm_pool_lvol));

  if (!lvm_volume_group_call_create_thin_volume_sync (group->lvm_volume_group,
                                                      arg_name,
                                                      arg_size,
                                                      pool_path,
                                                      null_asv (),
                                                      &result,
                                                      NULL,
                                                      &error))
    {
      g_dbus_error_strip_remote_error (error);
      g_dbus_method_invocation_return_error (invocation,
                                             COCKPIT_ERROR,
                                             COCKPIT_ERROR_FAILED,
                                             "%s", error->message);
      g_error_free (error);
    }
  else
    cockpit_storage_volume_group_complete_create_thin_pool_volume (object, invocation);

  return TRUE;
}
コード例 #2
0
ファイル: storagevolumegroup.c プロジェクト: finid/cockpit
static gboolean
handle_empty_device (CockpitStorageVolumeGroup *object,
                     GDBusMethodInvocation *invocation,
                     const gchar *arg_objpath)
{
  StorageVolumeGroup *group = STORAGE_VOLUME_GROUP(object);
  GError *error = NULL;
  const gchar *block_path = "/";

  if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
    return TRUE;

  StorageProvider *provider = storage_object_get_provider (group->object);
  Daemon *daemon = storage_provider_get_daemon (provider);
  GDBusObjectManagerServer *object_manager_server = daemon_get_object_manager (daemon);
  GDBusObjectManager *object_manager = G_DBUS_OBJECT_MANAGER (object_manager_server);

  StorageObject *block_object =
    STORAGE_OBJECT (g_dbus_object_manager_get_object (object_manager, arg_objpath));
  UDisksBlock *udisks_block = storage_object_get_udisks_block (block_object);

  if (udisks_block)
    block_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (udisks_block));

  g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (group->lvm_volume_group),
                                    G_MAXINT);

  if (!lvm_volume_group_call_empty_device_sync (group->lvm_volume_group,
                                                block_path,
                                                null_asv (),
                                                NULL,
                                                &error))
    {
      g_dbus_error_strip_remote_error (error);
      g_dbus_method_invocation_return_error (invocation,
                                             COCKPIT_ERROR,
                                             COCKPIT_ERROR_FAILED,
                                             "%s", error->message);
      g_error_free (error);
    }
  else
    cockpit_storage_volume_group_complete_empty_device (object, invocation);

  g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (group->lvm_volume_group),
                                    -1);

  return TRUE;
}
コード例 #3
0
ファイル: accounts.c プロジェクト: magcius/cockpit
static void
user_removed (ActUserManager *um,
              ActUser *user,
              Accounts *accounts)
{
  GDBusObjectManagerServer *object_manager_server = daemon_get_object_manager (daemon_get ());

  Account *acc = g_hash_table_lookup (accounts->act_user_to_account, user);
  if (acc)
    {
      account_update (acc, NULL);
      g_dbus_object_manager_server_unexport (object_manager_server,
         g_dbus_object_get_object_path (g_dbus_interface_get_object (G_DBUS_INTERFACE (acc))));
      g_hash_table_remove (accounts->act_user_to_account, user);
    }
}
コード例 #4
0
ファイル: setting.c プロジェクト: tschaefer/loom
void
setting_export (Setting *setting)
{
  g_return_if_fail (IS_SETTING (setting));

  GDBusObjectManagerServer *object_manager;
  object_manager = daemon_get_object_manager (setting->daemon);

  if (g_dbus_interface_get_object (G_DBUS_INTERFACE (setting)) == NULL)
    {
      LoomObjectSkeleton *object = NULL;

      object = loom_object_skeleton_new ("/org/blackox/Loom/Setting");
      loom_object_skeleton_set_setting (object, LOOM_SETTING (setting));
      g_dbus_object_manager_server_export_uniquely (object_manager,
                                               G_DBUS_OBJECT_SKELETON (object));
      g_object_unref (object);
    }
}
コード例 #5
0
ファイル: network.c プロジェクト: finid/cockpit
static void
on_nm_device_added (NMClient *client,
                    NMDevice *device,
                    gpointer user_data)
{
  Network *self = user_data;
  Netinterface *iface;
  CockpitNetworkNetinterface *cockpit_iface;
  const char *iface_name;
  Daemon *daemon;
  gs_unref_object CockpitObjectSkeleton *object = NULL;
  gs_free char *path = NULL;

  g_assert (client != NULL);
  g_assert (self != NULL);

  iface_name = nm_device_get_iface (device);
  if (!iface_name)
    return;

  iface = g_hash_table_lookup (self->ifname_to_netinterface, iface_name);
  if (iface != NULL)
    return;

  iface = (Netinterface*)netinterface_new (self, iface_name);
  cockpit_iface = COCKPIT_NETWORK_NETINTERFACE (iface);
  g_hash_table_insert (self->ifname_to_netinterface, g_strdup (iface_name), iface);
  path = utils_generate_object_path ("/com/redhat/Cockpit/Network", iface_name);
  object = cockpit_object_skeleton_new (path);
  daemon = network_get_daemon (self);
  cockpit_object_skeleton_set_network_netinterface (object, cockpit_iface);
  g_dbus_object_manager_server_export (daemon_get_object_manager (daemon),
                                       G_DBUS_OBJECT_SKELETON (object));

  g_signal_connect (device, "state-changed", G_CALLBACK(on_nm_device_state_changed),
                    self);
  synchronize_device (self, device);
}
コード例 #6
0
ファイル: daemon.c プロジェクト: BillTheBest/cockpit
static void
daemon_get_property (GObject *object,
                     guint prop_id,
                     GValue *value,
                     GParamSpec *pspec)
{
  Daemon *daemon = DAEMON (object);

  switch (prop_id)
    {
    case PROP_CONNECTION:
      g_value_set_object (value, daemon_get_connection (daemon));
      break;

    case PROP_OBJECT_MANAGER:
      g_value_set_object (value, daemon_get_object_manager (daemon));
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}
コード例 #7
0
ファイル: accounts.c プロジェクト: magcius/cockpit
static void
user_added (ActUserManager *um,
            ActUser *user,
            Accounts *accounts)
{
  if (act_user_is_system_account (user))
    return;

  GDBusObjectManagerServer *object_manager_server = daemon_get_object_manager (daemon_get ());

  CockpitAccount *acc = account_new ();
  account_update (ACCOUNT (acc), user);

  gs_free gchar *path =
    utils_generate_object_path ("/com/redhat/Cockpit/Accounts",
                                cockpit_account_get_user_name (acc));
  gs_unref_object CockpitObjectSkeleton *obj = cockpit_object_skeleton_new (path);
  cockpit_object_skeleton_set_account (obj, acc);
  g_dbus_object_manager_server_export_uniquely (object_manager_server,
                                                G_DBUS_OBJECT_SKELETON (obj));

  g_hash_table_insert (accounts->act_user_to_account, user, ACCOUNT(acc));
}
コード例 #8
0
static gboolean
handle_volume_group_create (CockpitStorageManager *object,
                            GDBusMethodInvocation *invocation,
                            const gchar *arg_name,
                            const gchar *const *arg_blocks)
{
  StorageManager *storage_manager = STORAGE_MANAGER(object);
  GDBusObjectManagerServer *object_manager_server = daemon_get_object_manager (storage_manager->daemon);
  GDBusObjectManager *object_manager = G_DBUS_OBJECT_MANAGER (object_manager_server);

  if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
    return TRUE;

  GError *error = NULL;

  int n_blocks = 0;
  for (int i = 0; arg_blocks[i]; i++)
    n_blocks += 1;

  const gchar *udisks_blocks[n_blocks + 1];

  for (int i = 0; arg_blocks[i]; i++)
    {
      StorageObject *stobj =
        STORAGE_OBJECT (g_dbus_object_manager_get_object (object_manager, arg_blocks[i]));
      UDisksBlock *block = storage_object_get_udisks_block (stobj);
      if (block)
        udisks_blocks[i] = g_dbus_proxy_get_object_path (G_DBUS_PROXY(block));
      else
        udisks_blocks[i] = "XXX";
    }

  udisks_blocks[n_blocks] = NULL;

  if (storage_manager->lvm_manager == NULL)
    {
      g_dbus_method_invocation_return_error (invocation,
                                             COCKPIT_ERROR,
                                             COCKPIT_ERROR_FAILED,
                                             "storaged daemon is not running");
      return TRUE;
    }

  if (!lvm_manager_call_volume_group_create_sync (storage_manager->lvm_manager,
                                                  arg_name,
                                                  udisks_blocks,
                                                  null_asv (),
                                                  NULL,
                                                  NULL,
                                                  &error))
    {
      g_dbus_error_strip_remote_error (error);
      g_dbus_method_invocation_return_error (invocation,
                                             COCKPIT_ERROR,
                                             COCKPIT_ERROR_FAILED,
                                             "%s", error->message);
      g_error_free (error);
      return TRUE;
    }

  cockpit_storage_manager_complete_volume_group_create (object, invocation);
  return TRUE;
}
コード例 #9
0
static gboolean
handle_mdraid_create (CockpitStorageManager *object,
                      GDBusMethodInvocation *invocation,
                      const gchar *const *arg_blocks,
                      const gchar *arg_level,
                      const gchar *arg_name,
                      guint64 arg_chunk)
{
  StorageManager *storage_manager = STORAGE_MANAGER(object);
  GDBusObjectManagerServer *object_manager_server = daemon_get_object_manager (storage_manager->daemon);
  GDBusObjectManager *object_manager = G_DBUS_OBJECT_MANAGER (object_manager_server);

  if (!auth_check_sender_role (invocation, COCKPIT_ROLE_STORAGE_ADMIN))
    return TRUE;

  GError *error = NULL;

  int n_blocks = 0;
  for (int i = 0; arg_blocks[i]; i++)
    n_blocks += 1;

  const gchar *udisks_blocks[n_blocks + 1];

  for (int i = 0; arg_blocks[i]; i++)
    {
      StorageObject *stobj =
        STORAGE_OBJECT (g_dbus_object_manager_get_object (object_manager, arg_blocks[i]));
      UDisksBlock *block = storage_object_get_udisks_block (stobj);
      if (block)
        udisks_blocks[i] = g_dbus_proxy_get_object_path (G_DBUS_PROXY(block));
      else
        udisks_blocks[i] = "XXX";
    }

  udisks_blocks[n_blocks] = NULL;

  UDisksManager *manager = udisks_client_get_manager (storage_manager->udisks);
  if (manager == NULL)
    {
      g_dbus_method_invocation_return_error (invocation,
                                             COCKPIT_ERROR,
                                             COCKPIT_ERROR_FAILED,
                                             "UDisks daemon is not running");
      return TRUE;
    }

  GVariantBuilder options;
  g_variant_builder_init (&options, G_VARIANT_TYPE("a{sv}"));

  if (!udisks_manager_call_mdraid_create_sync (manager,
                                               udisks_blocks,
                                               arg_level,
                                               arg_name,
                                               arg_chunk,
                                               null_asv (),
                                               NULL,
                                               NULL,
                                               &error))
    {
      g_dbus_error_strip_remote_error (error);
      g_dbus_method_invocation_return_error (invocation,
                                             COCKPIT_ERROR,
                                             COCKPIT_ERROR_FAILED,
                                             "%s", error->message);
      g_error_free (error);
      return TRUE;
    }

  cockpit_storage_manager_complete_mdraid_create (object, invocation);
  return TRUE;
}
コード例 #10
0
ファイル: daemon.c プロジェクト: BillTheBest/cockpit
static void
daemon_constructed (GObject *_object)
{
  Daemon *daemon = DAEMON (_object);
  CockpitManager *manager;
  CockpitMachines *machines;
  CockpitResourceMonitor *monitor;
  CockpitMultiResourceMonitor *multi_monitor;
  CockpitRealms *realms;
  CockpitServices *services;
  CockpitJournal *journal;
  CockpitAccounts *accounts;
  CockpitStorageManager *storage_manager;
  CockpitObjectSkeleton *object = NULL;

  g_assert (_daemon_instance == NULL);
  _daemon_instance = daemon;

  daemon->system_bus_proxy = g_dbus_proxy_new_sync (daemon->connection, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
                                                    NULL, "org.freedesktop.DBus",
                                                    "/org/freedesktop/DBus",
                                                    "org.freedesktop.DBus", NULL, NULL);
  g_assert (daemon->system_bus_proxy != NULL);

  daemon->object_manager = g_dbus_object_manager_server_new ("/com/redhat/Cockpit");

  /* /com/redhat/Cockpit/Machines */
  machines = machines_new (daemon_get_object_manager (daemon));
  daemon->machines = MACHINES (machines);
  object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/Machines");
  cockpit_object_skeleton_set_machines (object, machines);
  g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
  g_object_unref (machines);
  g_object_unref (object);

  /* /com/redhat/Cockpit/Manager */
  manager = manager_new (daemon);
  object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/Manager");
  cockpit_object_skeleton_set_manager (object, manager);
  g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
  g_object_unref (manager);
  g_object_unref (object);

  /* /com/redhat/Cockpit/CpuMonitor */
  monitor = cpu_monitor_new (daemon);
  object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/CpuMonitor");
  cockpit_object_skeleton_set_resource_monitor (object, monitor);
  g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
  g_object_unref (monitor);
  g_object_unref (object);

  /* /com/redhat/Cockpit/MemoryMonitor */
  monitor = memory_monitor_new (daemon);
  object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/MemoryMonitor");
  cockpit_object_skeleton_set_resource_monitor (object, monitor);
  g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
  g_object_unref (monitor);
  g_object_unref (object);

  /* /com/redhat/Cockpit/NetworkMonitor */
  monitor = network_monitor_new (daemon);
  object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/NetworkMonitor");
  cockpit_object_skeleton_set_resource_monitor (object, monitor);
  g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
  g_object_unref (monitor);
  g_object_unref (object);

  /* /com/redhat/Cockpit/DiskIOMonitor */
  monitor = disk_io_monitor_new (daemon);
  object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/DiskIOMonitor");
  cockpit_object_skeleton_set_resource_monitor (object, monitor);
  g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
  g_object_unref (monitor);
  g_object_unref (object);

  /* /com/redhat/Cockpit/LxcMonitor */
  multi_monitor = cgroup_monitor_new (G_OBJECT (daemon));
  object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/LxcMonitor");
  cockpit_object_skeleton_set_multi_resource_monitor (object, multi_monitor);
  g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
  g_object_unref (multi_monitor);
  g_object_unref (object);

  /* /com/redhat/Cockpit/NetdevMonitor */
  multi_monitor = netdev_monitor_new (G_OBJECT (daemon));
  object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/NetdevMonitor");
  cockpit_object_skeleton_set_multi_resource_monitor (object, multi_monitor);
  g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
  g_object_unref (multi_monitor);
  g_object_unref (object);

  /* /com/redhat/Cockpit/Realms */
  realms = realms_new (daemon);
  object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/Realms");
  cockpit_object_skeleton_set_realms (object, realms);
  g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
  g_object_unref (realms);
  g_object_unref (object);

  /* /com/redhat/Cockpit/Services */
  services = services_new (daemon);
  object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/Services");
  cockpit_object_skeleton_set_services (object, services);
  g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
  g_object_unref (services);
  g_object_unref (object);

  /* /com/redhat/Cockpit/Journal */
  journal = journal_new ();
  object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/Journal");
  cockpit_object_skeleton_set_journal (object, journal);
  g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
  g_object_unref (journal);

  /* /com/redhat/Cockpit/Accounts */
  accounts = accounts_new ();
  object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/Accounts");
  cockpit_object_skeleton_set_accounts (object, accounts);
  g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
  g_object_unref (accounts);

  g_object_unref (object);

  /* /com/redhat/Cockpit/Storage/Manager */
  storage_manager = storage_manager_new (daemon);
  object = cockpit_object_skeleton_new ("/com/redhat/Cockpit/Storage/Manager");
  cockpit_object_skeleton_set_storage_manager (object, storage_manager);
  g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object));
  g_object_unref (storage_manager);
  g_object_unref (object);

  daemon->storage_provider = storage_provider_new (daemon);

  /* Export the ObjectManager */
  g_dbus_object_manager_server_set_connection (daemon->object_manager, daemon->connection);

  daemon->tick_timeout_id = g_timeout_add_seconds (1, on_timeout, daemon);

  if (G_OBJECT_CLASS (daemon_parent_class)->constructed != NULL)
    G_OBJECT_CLASS (daemon_parent_class)->constructed (_object);
}
コード例 #11
0
static void
provider_update_jobs (StorageProvider *provider)
{
  GDBusObjectManagerServer *object_manager;
  GList *udisks_objects;
  GList *lvm_objects;
  GList *all_objects;
  GList *wanted;
  GList *added, *removed;
  GList *l;

  object_manager = G_DBUS_OBJECT_MANAGER_SERVER (daemon_get_object_manager (provider->daemon));
  udisks_objects = g_dbus_object_manager_get_objects (udisks_client_get_object_manager (provider->udisks_client));
  lvm_objects = g_dbus_object_manager_get_objects (provider->lvm_objman);
  all_objects = g_list_concat (udisks_objects, lvm_objects);

  wanted = NULL;
  for (l = all_objects; l != NULL; l = l->next)
    {
      if (!UDISKS_IS_OBJECT (l->data))
        continue;

      UDisksObject *object = UDISKS_OBJECT (l->data);
      UDisksJob *job;

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

      const gchar *operation = udisks_job_get_operation (job);

      if (strcmp (operation, "format-mkfs") != 0
          && strcmp (operation, "format-erase") != 0
          && strcmp (operation, "lvm-vg-empty-device") != 0)
        continue;

      wanted = g_list_prepend (wanted, g_object_ref (job));
    }

  wanted = g_list_sort (wanted, (GCompareFunc)_udisks_job_compare_func);
  provider->jobs = g_list_sort (provider->jobs, (GCompareFunc)_udisks_job_compare_func);
  diff_sorted_lists (provider->jobs, wanted, (GCompareFunc)_udisks_job_compare_func,
                     &added, &removed, NULL);

  for (l = removed; l != NULL; l = l->next)
    {
      UDisksJob *job = UDISKS_JOB (l->data);
      CockpitJob *object;

      object = g_hash_table_lookup (provider->hash_job_to_storage_job, job);
      if (object == NULL)
        {
          g_warning ("No object for job %p", job);
        }
      else
        {
          g_warn_if_fail (g_dbus_object_manager_server_unexport (object_manager,
                                                                 g_dbus_object_get_object_path (G_DBUS_OBJECT (object))));
          g_hash_table_remove (provider->hash_job_to_storage_job, job);
        }

      provider->jobs = g_list_remove (provider->jobs, job);
      g_object_unref (job);
    }

  for (l = added; l != NULL; l = l->next)
    {
      UDisksJob *job = UDISKS_JOB (l->data);
      CockpitObjectSkeleton *object;
      CockpitJob *cockpit_job;
      gchar *object_path;

      object_path = utils_generate_object_path ("/com/redhat/Cockpit/Jobs",
                                                udisks_job_get_operation (job));

      cockpit_job = storage_job_new (provider, job);
      object = cockpit_object_skeleton_new (object_path);
      cockpit_object_skeleton_set_job (object, cockpit_job);
      g_object_unref (cockpit_job);

      g_free (object_path);

      g_warn_if_fail (g_hash_table_lookup (provider->hash_job_to_storage_job, job) == NULL);
      g_hash_table_insert (provider->hash_job_to_storage_job,
                           g_object_ref (job),
                           object);

      g_dbus_object_manager_server_export_uniquely (object_manager, G_DBUS_OBJECT_SKELETON (object));

      provider->jobs = g_list_prepend (provider->jobs, g_object_ref (job));
    }

  g_list_free (added);
  g_list_free (removed);
  g_list_free_full (all_objects, g_object_unref);
  g_list_free_full (wanted, g_object_unref);
}
コード例 #12
0
static void
provider_update_objects (StorageProvider *provider)
{
  GDBusObjectManagerServer *object_manager;
  GList *udisks_objects;
  GList *lvm_objects;
  GList *wanted;
  GList *added, *removed;
  GList *l;

  object_manager = G_DBUS_OBJECT_MANAGER_SERVER (daemon_get_object_manager (provider->daemon));
  udisks_objects = g_dbus_object_manager_get_objects (udisks_client_get_object_manager (provider->udisks_client));
  lvm_objects = g_dbus_object_manager_get_objects (provider->lvm_objman);

  wanted = NULL;
  for (l = udisks_objects; l != NULL; l = l->next)
    {
      GDBusInterface *iface = get_udisk_iface (UDISKS_OBJECT (l->data));
      if (iface == NULL)
        continue;

      wanted = g_list_prepend (wanted, g_object_ref (iface));
    }
  for (l = lvm_objects; l != NULL; l = l->next)
    {
      if (!LVM_IS_OBJECT (l->data))
        continue;

      GDBusInterface *iface = get_lvm_iface (LVM_OBJECT (l->data));
      if (iface == NULL)
        continue;

      wanted = g_list_prepend (wanted, g_object_ref (iface));
    }

  wanted = g_list_sort (wanted, (GCompareFunc)udisks_iface_compare_func);
  provider->ifaces = g_list_sort (provider->ifaces, (GCompareFunc)udisks_iface_compare_func);
  diff_sorted_lists (provider->ifaces, wanted, (GCompareFunc)udisks_iface_compare_func,
                     &added, &removed, NULL);

  for (l = removed; l != NULL; l = l->next)
    {
      GDBusInterface *iface = G_DBUS_INTERFACE (l->data);
      StorageObject *object;

      object = g_hash_table_lookup (provider->hash_interface_to_storage_object, iface);
      g_warn_if_fail (object != NULL);
      if (object)
        {
          g_warn_if_fail (g_dbus_object_manager_server_unexport (object_manager,
                          g_dbus_object_get_object_path (G_DBUS_OBJECT (object))));
        }

      g_hash_table_remove (provider->hash_interface_to_storage_object, iface);
      provider->ifaces = g_list_remove (provider->ifaces, iface);
      g_object_unref (iface);
    }

  for (l = added; l != NULL; l = l->next)
    {
      GDBusInterface *iface = G_DBUS_INTERFACE (l->data);
      StorageObject *object = make_storage_object (provider, iface);

      g_warn_if_fail (g_hash_table_lookup (provider->hash_interface_to_storage_object, iface) == NULL);
      g_hash_table_insert (provider->hash_interface_to_storage_object,
                           g_object_ref (iface),
                           object);

      gs_free gchar *object_path = storage_object_make_object_path (object);
      g_dbus_object_skeleton_set_object_path (G_DBUS_OBJECT_SKELETON (object), object_path);
      g_dbus_object_manager_server_export_uniquely (object_manager, G_DBUS_OBJECT_SKELETON (object));

      provider->ifaces = g_list_prepend (provider->ifaces, g_object_ref (iface));
    }

  g_list_free (added);
  g_list_free (removed);
  g_list_free_full (udisks_objects, g_object_unref);
  g_list_free_full (lvm_objects, g_object_unref);
  g_list_free_full (wanted, g_object_unref);
}