コード例 #1
0
/**
 * storaged_linux_block_object_trigger_uevent:
 * @object: A #StoragedLinuxBlockObject.
 *
 * Triggers a 'change' uevent in the kernel.
 *
 * The triggered event will bubble up from the kernel through the udev
 * stack and will eventually be received by the storaged daemon process
 * itself. This method does not wait for the event to be received.
 */
void
storaged_linux_block_object_trigger_uevent (StoragedLinuxBlockObject *object)
{
    gchar* path = NULL;
    gint fd = -1;

    g_return_if_fail (STORAGED_IS_LINUX_BLOCK_OBJECT (object));

    /* TODO: would be nice with a variant to wait until the request uevent has been received by ourselves */

    path = g_strconcat (g_udev_device_get_sysfs_path (object->device->udev_device), "/uevent", NULL);
    fd = open (path, O_WRONLY);
    if (fd < 0)
    {
        storaged_warning ("Error opening %s: %m", path);
        goto out;
    }

    if (write (fd, "change", sizeof "change" - 1) != sizeof "change" - 1)
    {
        storaged_warning ("Error writing 'change' to file %s: %m", path);
        goto out;
    }

out:
    if (fd >= 0)
        close (fd);
    g_free (path);
}
コード例 #2
0
static gboolean
btrfs_block_check (StoragedObject *object)
{
  const gchar *fs_type = NULL;
  StoragedLinuxDevice *device = NULL;

  g_return_val_if_fail (STORAGED_IS_LINUX_BLOCK_OBJECT (object), FALSE);

  /* Check filesystem type from udev property. */
  device = storaged_linux_block_object_get_device (STORAGED_LINUX_BLOCK_OBJECT (object));
  fs_type = g_udev_device_get_property (device->udev_device, "ID_FS_TYPE");

  return g_strcmp0 (fs_type, "btrfs") == 0;
}
コード例 #3
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);
        }
    }
}
コード例 #4
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;
}
コード例 #5
0
/**
 * storaged_linux_filesystem_btrfs_update:
 * @l_fs_btrfs: A #StoragedLinuxFilesystemBTRFS.
 * @object: The enclosing #StoragedLlinuxDriveObject instance.
 *
 * Updates the interface.
 *
 * Returns: %TRUE if the configuration has changed, %FALSE otherwise.
 */
gboolean
storaged_linux_filesystem_btrfs_update (StoragedLinuxFilesystemBTRFS *l_fs_btrfs,
                                        StoragedLinuxBlockObject     *object)
{
  StoragedFilesystemBTRFS *fs_btrfs = STORAGED_FILESYSTEM_BTRFS (l_fs_btrfs);
  BDBtrfsFilesystemInfo *btrfs_info = NULL;
  GError *error = NULL;
  gchar *dev_file = NULL;
  gboolean rval = FALSE;

  g_return_val_if_fail (STORAGED_IS_LINUX_FILESYSTEM_BTRFS (fs_btrfs), FALSE);
  g_return_val_if_fail (STORAGED_IS_LINUX_BLOCK_OBJECT (object), FALSE);

  dev_file = storaged_linux_block_object_get_device_file (object);
  if (! dev_file)
    {
      rval = FALSE;
      goto out;
    }

  btrfs_info = bd_btrfs_filesystem_info (dev_file, &error);

  if (! btrfs_info)
    {
      storaged_error ("Can't get BTRFS filesystem info for %s", dev_file);
      rval = FALSE;
      goto out;
    }

  /* Update the interface */
  storaged_filesystem_btrfs_set_label (fs_btrfs, btrfs_info->label);
  storaged_filesystem_btrfs_set_uuid (fs_btrfs, btrfs_info->uuid);
  storaged_filesystem_btrfs_set_num_devices (fs_btrfs, btrfs_info->num_devices);
  storaged_filesystem_btrfs_set_used (fs_btrfs, btrfs_info->used);

out:
  if (btrfs_info)
    bd_btrfs_filesystem_info_free (btrfs_info);
  if (error)
    g_error_free (error);
  g_free ((gpointer) dev_file);

  return rval;
}
コード例 #6
0
static gboolean
bcache_block_check (StoragedObject *object)
{
  const gchar *devname = NULL;
  StoragedLinuxDevice *device = NULL;
  gboolean rval = FALSE;

  g_return_val_if_fail (STORAGED_IS_LINUX_BLOCK_OBJECT (object), FALSE);

  /* Check device name */
  device = storaged_linux_block_object_get_device (STORAGED_LINUX_BLOCK_OBJECT (object));
  devname = g_strdup (g_udev_device_get_device_file (device->udev_device));

  rval = g_str_has_prefix (devname, "/dev/bcache");

  g_free ((gpointer) devname);

  return rval;
}
コード例 #7
0
gboolean
storaged_linux_block_bcache_update (StoragedLinuxBlockBcache  *block,
                                    StoragedLinuxBlockObject  *object)
{
  StoragedBlockBcache *iface = STORAGED_BLOCK_BCACHE (block);
  GError *error = NULL;
  gchar *dev_file = NULL;
  gboolean rval = FALSE;
  BDKBDBcacheStats *stats;
  const gchar* mode = NULL;

  g_return_val_if_fail (STORAGED_IS_LINUX_BLOCK_BCACHE (block), FALSE);
  g_return_val_if_fail (STORAGED_IS_LINUX_BLOCK_OBJECT (object), FALSE);

  dev_file = storaged_linux_block_object_get_device_file (object);

  stats = bd_kbd_bcache_status (dev_file, &error);
  mode = bd_kbd_bcache_get_mode_str(bd_kbd_bcache_get_mode(dev_file, &error), &error);
  if (! stats || ! mode)
    {
      storaged_error ("Can't get Bcache block device info for %s", dev_file);
      rval = FALSE;
      goto out;
    }

  storaged_block_bcache_set_mode (iface, mode);
  storaged_block_bcache_set_state (iface, stats->state);
  storaged_block_bcache_set_block_size (iface, stats->block_size);
  storaged_block_bcache_set_cache_size (iface, stats->cache_size);
  storaged_block_bcache_set_cache_used (iface, stats->cache_used);
  storaged_block_bcache_set_hits (iface, stats->hits);
  storaged_block_bcache_set_misses (iface, stats->misses);
  storaged_block_bcache_set_bypass_hits (iface, stats->bypass_hits);
  storaged_block_bcache_set_bypass_misses (iface, stats->bypass_misses);
out:
  if (stats)
    bd_kbd_bcache_stats_free (stats);
  if (error)
    g_error_free (error);
  g_free (dev_file);

  return rval;
}
コード例 #8
0
/**
 * storaged_linux_block_object_reread_partition_table:
 * @object: A #StoragedLinuxBlockObject.
 *
 * Requests the kernel to re-read the partition table for @object.
 *
 * The events from any change this may cause will bubble up from the
 * kernel through the udev stack and will eventually be received by
 * the storaged daemon process itself. This method does not wait for the
 * event to be received.
 */
void
storaged_linux_block_object_reread_partition_table (StoragedLinuxBlockObject *object)
{
    const gchar *device_file;
    gint fd;

    g_return_if_fail (STORAGED_IS_LINUX_BLOCK_OBJECT (object));

    device_file = g_udev_device_get_device_file (object->device->udev_device);
    fd = open (device_file, O_RDONLY);
    if (fd == -1)
    {
        storaged_warning ("Error opening %s: %m", device_file);
    }
    else
    {
        if (ioctl (fd, BLKRRPART) != 0)
        {
            storaged_warning ("Error issuing BLKRRPART to %s: %m", device_file);
        }
        close (fd);
    }
}
コード例 #9
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;
}
コード例 #10
0
/**
 * storaged_linux_block_object_get_device:
 * @object: A #StoragedLinuxBlockObject.
 *
 * Gets the current #StoragedLinuxDevice for @object. Connect to
 * #GObject::notify to track changes to the #StoragedLinuxBlockObject:device
 * property.
 *
 * Returns: A #StoragedLinuxDevice. Free with g_object_unref().
 */
StoragedLinuxDevice *
storaged_linux_block_object_get_device (StoragedLinuxBlockObject *object)
{
    g_return_val_if_fail (STORAGED_IS_LINUX_BLOCK_OBJECT (object), NULL);
    return g_object_ref (object->device);
}
コード例 #11
0
/**
 * storaged_linux_block_object_get_daemon:
 * @object: A #StoragedLinuxBlockObject.
 *
 * Gets the daemon used by @object.
 *
 * Returns: A #StoragedDaemon. Do not free, the object is owned by @object.
 */
StoragedDaemon *
storaged_linux_block_object_get_daemon (StoragedLinuxBlockObject *object)
{
    g_return_val_if_fail (STORAGED_IS_LINUX_BLOCK_OBJECT (object), NULL);
    return object->daemon;
}
コード例 #12
0
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);
}