/* called with lock held */ static void handle_block_uevent_for_block (UDisksLinuxProvider *provider, const gchar *action, UDisksLinuxDevice *device) { const gchar *sysfs_path; UDisksLinuxBlockObject *object; UDisksDaemon *daemon; daemon = udisks_provider_get_daemon (UDISKS_PROVIDER (provider)); sysfs_path = g_udev_device_get_sysfs_path (device->udev_device); if (g_strcmp0 (action, "remove") == 0) { object = g_hash_table_lookup (provider->sysfs_to_block, sysfs_path); if (object != NULL) { g_dbus_object_manager_server_unexport (udisks_daemon_get_object_manager (daemon), g_dbus_object_get_object_path (G_DBUS_OBJECT (object))); g_warn_if_fail (g_hash_table_remove (provider->sysfs_to_block, sysfs_path)); } } else { object = g_hash_table_lookup (provider->sysfs_to_block, sysfs_path); if (object != NULL) { udisks_linux_block_object_uevent (object, action, device); } else { object = udisks_linux_block_object_new (daemon, device); g_dbus_object_manager_server_export_uniquely (udisks_daemon_get_object_manager (daemon), G_DBUS_OBJECT_SKELETON (object)); g_hash_table_insert (provider->sysfs_to_block, g_strdup (sysfs_path), object); } } }
/** * udisks_linux_drive_object_get_block: * @object: A #UDisksLinuxDriveObject. * @get_hw: If the drive is multipath, set to %TRUE to get a path device instead of the multipath device. * * Gets a #UDisksLinuxBlockObject representing a block device associated with @object. * * Returns: A #UDisksLinuxBlockObject or %NULL. The returned object * must be freed with g_object_unref(). */ UDisksLinuxBlockObject * udisks_linux_drive_object_get_block (UDisksLinuxDriveObject *object, gboolean get_hw) { GDBusObjectManagerServer *object_manager; UDisksLinuxBlockObject *ret; GList *objects; GList *l; /* TODO: actually look at @get_hw */ ret = NULL; object_manager = udisks_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); UDisksBlock *block; UDisksLinuxDevice *device; gboolean is_disk; if (!UDISKS_IS_LINUX_BLOCK_OBJECT (iter_object)) continue; device = udisks_linux_block_object_get_device (UDISKS_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 = udisks_object_peek_block (UDISKS_OBJECT (iter_object)); if (g_strcmp0 (udisks_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; }
/** * udisks_linux_drive_object_get_siblings: * @object: A #UDisksLinuxDriveObject. * * Gets the siblings for @object, if any. * * Returns: (transfer full) (element-type UDisksLinuxDriveObject): A list of #UDisksLinuxDriveObject * instances. The returned list should be freed with g_list_free() after each element has been * freed with g_object_unref(). */ GList * udisks_linux_drive_object_get_siblings (UDisksLinuxDriveObject *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 = udisks_drive_dup_sibling_id (object->iface_drive); if (sibling_id == NULL || strlen (sibling_id) == 0) goto out; object_manager = udisks_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); UDisksLinuxDriveObject *iter_linux_drive_object; if (!UDISKS_IS_LINUX_DRIVE_OBJECT (iter_object)) continue; iter_linux_drive_object = UDISKS_LINUX_DRIVE_OBJECT (iter_object); if (iter_linux_drive_object->iface_drive != NULL && g_strcmp0 (udisks_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; }
static void maybe_remove_mdraid_object (UDisksLinuxProvider *provider, UDisksLinuxMDRaidObject *object) { gchar *object_uuid = NULL; UDisksDaemon *daemon = NULL; /* remove the object only if there are no devices left */ if (udisks_linux_mdraid_object_have_devices (object)) goto out; daemon = udisks_provider_get_daemon (UDISKS_PROVIDER (provider)); object_uuid = g_strdup (udisks_linux_mdraid_object_get_uuid (object)); g_dbus_object_manager_server_unexport (udisks_daemon_get_object_manager (daemon), g_dbus_object_get_object_path (G_DBUS_OBJECT (object))); g_warn_if_fail (g_hash_table_remove (provider->uuid_to_mdraid, object_uuid)); out: g_free (object_uuid); }
/** * udisks_linux_drive_object_is_not_in_use: * @object: A #UDisksLinuxDriveObject. * @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 udisks_linux_drive_object_is_not_in_use (UDisksLinuxDriveObject *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 (UDISKS_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 = udisks_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); UDisksBlock *block; UDisksFilesystem *filesystem; if (!UDISKS_IS_LINUX_BLOCK_OBJECT (iter_object)) continue; block = udisks_object_peek_block (UDISKS_OBJECT (iter_object)); filesystem = udisks_object_peek_filesystem (UDISKS_OBJECT (iter_object)); if (g_strcmp0 (udisks_block_get_drive (block), drive_object_path) != 0) continue; /* bail if block device is mounted */ if (filesystem != NULL) { if (g_strv_length ((gchar **) udisks_filesystem_get_mount_points (filesystem)) > 0) { g_set_error (error, UDISKS_ERROR, UDISKS_ERROR_DEVICE_BUSY, "Device %s is mounted", udisks_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, UDISKS_ERROR, UDISKS_ERROR_DEVICE_BUSY, "Encrypted device %s is unlocked", udisks_block_get_preferred_device (block)); ret = FALSE; goto out; } } out: g_list_free_full (objects, g_object_unref); return ret; }
/* called with lock held */ static void handle_block_uevent_for_drive (UDisksLinuxProvider *provider, const gchar *action, UDisksLinuxDevice *device) { UDisksLinuxDriveObject *object; UDisksDaemon *daemon; const gchar *sysfs_path; gchar *vpd; vpd = NULL; daemon = udisks_provider_get_daemon (UDISKS_PROVIDER (provider)); sysfs_path = g_udev_device_get_sysfs_path (device->udev_device); if (g_strcmp0 (action, "remove") == 0) { object = g_hash_table_lookup (provider->sysfs_path_to_drive, sysfs_path); if (object != NULL) { GList *devices; udisks_linux_drive_object_uevent (object, action, device); g_warn_if_fail (g_hash_table_remove (provider->sysfs_path_to_drive, sysfs_path)); devices = udisks_linux_drive_object_get_devices (object); if (devices == NULL) { const gchar *existing_vpd; existing_vpd = g_object_get_data (G_OBJECT (object), "x-vpd"); g_dbus_object_manager_server_unexport (udisks_daemon_get_object_manager (daemon), g_dbus_object_get_object_path (G_DBUS_OBJECT (object))); g_warn_if_fail (g_hash_table_remove (provider->vpd_to_drive, existing_vpd)); } g_list_foreach (devices, (GFunc) g_object_unref, NULL); g_list_free (devices); } } else { if (!udisks_linux_drive_object_should_include_device (provider->gudev_client, device, &vpd)) goto out; if (vpd == NULL) { udisks_debug ("Ignoring block device %s with no serial or WWN", g_udev_device_get_sysfs_path (device->udev_device)); goto out; } object = g_hash_table_lookup (provider->vpd_to_drive, vpd); if (object != NULL) { if (g_hash_table_lookup (provider->sysfs_path_to_drive, sysfs_path) == NULL) g_hash_table_insert (provider->sysfs_path_to_drive, g_strdup (sysfs_path), object); udisks_linux_drive_object_uevent (object, action, device); } else { object = udisks_linux_drive_object_new (daemon, device); if (object != NULL) { g_object_set_data_full (G_OBJECT (object), "x-vpd", g_strdup (vpd), g_free); g_dbus_object_manager_server_export_uniquely (udisks_daemon_get_object_manager (daemon), G_DBUS_OBJECT_SKELETON (object)); g_hash_table_insert (provider->vpd_to_drive, g_strdup (vpd), object); g_hash_table_insert (provider->sysfs_path_to_drive, g_strdup (sysfs_path), object); /* schedule initial housekeeping for the drive unless coldplugging */ if (!provider->coldplug) { g_io_scheduler_push_job (perform_initial_housekeeping_for_drive, g_object_ref (object), (GDestroyNotify) g_object_unref, G_PRIORITY_DEFAULT, NULL); } } } } out: g_free (vpd); }
static void handle_block_uevent_for_mdraid_with_uuid (UDisksLinuxProvider *provider, const gchar *action, UDisksLinuxDevice *device, const gchar *uuid, gboolean is_member) { UDisksLinuxMDRaidObject *object; UDisksDaemon *daemon; const gchar *sysfs_path; daemon = udisks_provider_get_daemon (UDISKS_PROVIDER (provider)); sysfs_path = g_udev_device_get_sysfs_path (device->udev_device); /* if uuid is NULL or bogus, consider it a remove event */ if (uuid == NULL || g_strcmp0 (uuid, "00000000:00000000:00000000:00000000") == 0) action = "remove"; if (g_strcmp0 (action, "remove") == 0) { /* first check if this device was a member */ object = g_hash_table_lookup (provider->sysfs_path_to_mdraid_members, sysfs_path); if (object != NULL) { udisks_linux_mdraid_object_uevent (object, action, device, TRUE /* is_member */); g_warn_if_fail (g_hash_table_remove (provider->sysfs_path_to_mdraid_members, sysfs_path)); maybe_remove_mdraid_object (provider, object); } /* then check if the device was the raid device */ object = g_hash_table_lookup (provider->sysfs_path_to_mdraid, sysfs_path); if (object != NULL) { udisks_linux_mdraid_object_uevent (object, action, device, FALSE /* is_member */); g_warn_if_fail (g_hash_table_remove (provider->sysfs_path_to_mdraid, sysfs_path)); maybe_remove_mdraid_object (provider, object); } } else { if (uuid == NULL) goto out; object = g_hash_table_lookup (provider->uuid_to_mdraid, uuid); if (object != NULL) { if (is_member) { if (g_hash_table_lookup (provider->sysfs_path_to_mdraid_members, sysfs_path) == NULL) g_hash_table_insert (provider->sysfs_path_to_mdraid_members, g_strdup (sysfs_path), object); } else { if (g_hash_table_lookup (provider->sysfs_path_to_mdraid, sysfs_path) == NULL) g_hash_table_insert (provider->sysfs_path_to_mdraid, g_strdup (sysfs_path), object); } udisks_linux_mdraid_object_uevent (object, action, device, is_member); } else { object = udisks_linux_mdraid_object_new (daemon, uuid); udisks_linux_mdraid_object_uevent (object, action, device, is_member); g_dbus_object_manager_server_export_uniquely (udisks_daemon_get_object_manager (daemon), G_DBUS_OBJECT_SKELETON (object)); g_hash_table_insert (provider->uuid_to_mdraid, g_strdup (uuid), object); if (is_member) g_hash_table_insert (provider->sysfs_path_to_mdraid_members, g_strdup (sysfs_path), object); else g_hash_table_insert (provider->sysfs_path_to_mdraid, g_strdup (sysfs_path), object); } } out: ; }
static void udisks_linux_provider_start (UDisksProvider *_provider) { UDisksLinuxProvider *provider = UDISKS_LINUX_PROVIDER (_provider); UDisksDaemon *daemon; UDisksManager *manager; GList *devices; GList *udisks_devices; GList *l; guint n; provider->coldplug = TRUE; if (UDISKS_PROVIDER_CLASS (udisks_linux_provider_parent_class)->start != NULL) UDISKS_PROVIDER_CLASS (udisks_linux_provider_parent_class)->start (_provider); daemon = udisks_provider_get_daemon (UDISKS_PROVIDER (provider)); provider->manager_object = udisks_object_skeleton_new ("/org/freedesktop/UDisks2/Manager"); manager = udisks_linux_manager_new (daemon); udisks_object_skeleton_set_manager (provider->manager_object, manager); g_object_unref (manager); g_dbus_object_manager_server_export (udisks_daemon_get_object_manager (daemon), G_DBUS_OBJECT_SKELETON (provider->manager_object)); provider->sysfs_to_block = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref); provider->vpd_to_drive = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref); provider->sysfs_path_to_drive = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); provider->uuid_to_mdraid = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref); provider->sysfs_path_to_mdraid = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); provider->sysfs_path_to_mdraid_members = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); devices = g_udev_client_query_by_subsystem (provider->gudev_client, "block"); /* make sure we process sda before sdz and sdz before sdaa */ devices = g_list_sort (devices, (GCompareFunc) udev_device_name_cmp); /* probe for extra data we don't get from udev */ udisks_info ("Initialization (device probing)"); udisks_devices = NULL; for (l = devices; l != NULL; l = l->next) { GUdevDevice *device = G_UDEV_DEVICE (l->data); udisks_devices = g_list_prepend (udisks_devices, udisks_linux_device_new_sync (device)); } udisks_devices = g_list_reverse (udisks_devices); /* do two coldplug runs to handle dependencies between devices */ for (n = 0; n < 2; n++) { udisks_info ("Initialization (coldplug %d/2)", n + 1); for (l = udisks_devices; l != NULL; l = l->next) { UDisksLinuxDevice *device = l->data; udisks_linux_provider_handle_uevent (provider, "add", device); } } g_list_free_full (devices, g_object_unref); g_list_free_full (udisks_devices, g_object_unref); udisks_info ("Initialization complete"); /* schedule housekeeping for every 10 minutes */ provider->housekeeping_timeout = g_timeout_add_seconds (10*60, on_housekeeping_timeout, provider); /* ... and also do an initial run */ on_housekeeping_timeout (provider); provider->coldplug = FALSE; /* update Block:Configuration whenever fstab or crypttab entries are added or removed */ g_signal_connect (udisks_daemon_get_fstab_monitor (daemon), "entry-added", G_CALLBACK (fstab_monitor_on_entry_added), provider); g_signal_connect (udisks_daemon_get_fstab_monitor (daemon), "entry-removed", G_CALLBACK (fstab_monitor_on_entry_removed), provider); g_signal_connect (udisks_daemon_get_crypttab_monitor (daemon), "entry-added", G_CALLBACK (crypttab_monitor_on_entry_added), provider); g_signal_connect (udisks_daemon_get_crypttab_monitor (daemon), "entry-removed", G_CALLBACK (crypttab_monitor_on_entry_removed), provider); }
static void lvm_update_vgs (GObject *source_obj, GAsyncResult *result, gpointer user_data) { UDisksLVM2State *state; UDisksDaemon *daemon = UDISKS_DAEMON (source_obj); GDBusObjectManagerServer *manager; GTask *task = G_TASK (result); GError *error = NULL; VGsPVsData *data = g_task_propagate_pointer (task, &error); BDLVMVGdata **vgs = NULL; BDLVMPVdata **pvs = NULL; GHashTableIter vg_name_iter; gpointer key, value; const gchar *vg_name; if (!data) { if (error) udisks_warning ("LVM2 plugin: %s", error->message); else /* this should never happen */ udisks_warning ("LVM2 plugin: failure but no error when getting VGs!"); return; } vgs = data->vgs; pvs = data->pvs; /* free the data container (but not 'vgs' and 'pvs') */ g_free (data); manager = udisks_daemon_get_object_manager (daemon); state = get_module_state (daemon); /* Remove obsolete groups */ g_hash_table_iter_init (&vg_name_iter, udisks_lvm2_state_get_name_to_volume_group (state)); while (g_hash_table_iter_next (&vg_name_iter, &key, &value)) { UDisksLinuxVolumeGroupObject *group; gboolean found = FALSE; vg_name = key; group = value; for (BDLVMVGdata **vgs_p=vgs; !found && (*vgs_p); vgs_p++) found = g_strcmp0 ((*vgs_p)->name, vg_name) == 0; if (!found) { udisks_linux_volume_group_object_destroy (group); g_dbus_object_manager_server_unexport (manager, g_dbus_object_get_object_path (G_DBUS_OBJECT (group))); g_hash_table_iter_remove (&vg_name_iter); } } /* Add new groups and update existing groups */ for (BDLVMVGdata **vgs_p=vgs; *vgs_p; vgs_p++) { UDisksLinuxVolumeGroupObject *group; GSList *vg_pvs = NULL; vg_name = (*vgs_p)->name; group = g_hash_table_lookup (udisks_lvm2_state_get_name_to_volume_group (state), vg_name); if (group == NULL) { group = udisks_linux_volume_group_object_new (daemon, vg_name); g_hash_table_insert (udisks_lvm2_state_get_name_to_volume_group (state), g_strdup (vg_name), group); } for (BDLVMPVdata **pvs_p=pvs; *pvs_p; pvs_p++) if (g_strcmp0 ((*pvs_p)->vg_name, vg_name) == 0) vg_pvs = g_slist_prepend (vg_pvs, *pvs_p); udisks_linux_volume_group_object_update (group, *vgs_p, vg_pvs); } /* this is safe to do -- all BDLVMPVdata objects are still existing because the function that frees them is scheduled in main loop by the udisks_linux_volume_group_object_update() call above */ for (BDLVMPVdata **pvs_p=pvs; *pvs_p; pvs_p++) if ((*pvs_p)->vg_name == NULL) bd_lvm_pvdata_free (*pvs_p); /* only free the containers, the contents were passed further */ g_free (vgs); g_free (pvs); }