/** * 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); }
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; }
/** * 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); } } }
/** * 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_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; }
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; }
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; }
/** * 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); } }
/** * 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; }
/** * 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); }
/** * 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; }
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); }