summaryrefslogtreecommitdiff
path: root/src/udiskslinuxdrive.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/udiskslinuxdrive.c')
-rw-r--r--src/udiskslinuxdrive.c1093
1 files changed, 85 insertions, 1008 deletions
diff --git a/src/udiskslinuxdrive.c b/src/udiskslinuxdrive.c
index df42c98..9a6db9a 100644
--- a/src/udiskslinuxdrive.c
+++ b/src/udiskslinuxdrive.c
@@ -21,25 +21,32 @@
#include "config.h"
#include <glib/gi18n-lib.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
+#include <mntent.h>
-#include <atasmart.h>
+#include <glib/gstdio.h>
#include "udiskslogging.h"
-#include "udisksdaemon.h"
-#include "udisksdaemonutil.h"
#include "udiskslinuxprovider.h"
+#include "udiskslinuxdriveobject.h"
#include "udiskslinuxdrive.h"
#include "udiskslinuxblock.h"
+#include "udisksdaemon.h"
+#include "udiskscleanup.h"
+#include "udisksdaemonutil.h"
/**
* SECTION:udiskslinuxdrive
* @title: UDisksLinuxDrive
- * @short_description: Linux drives (ATA, SCSI, Software RAID, etc.)
+ * @short_description: Linux implementation of #UDisksDrive
*
- * Object corresponding to a Drive on Linux.
+ * This type provides an implementation of the #UDisksDrive interface
+ * on Linux.
*/
typedef struct _UDisksLinuxDriveClass UDisksLinuxDriveClass;
@@ -47,409 +54,53 @@ typedef struct _UDisksLinuxDriveClass UDisksLinuxDriveClass;
/**
* UDisksLinuxDrive:
*
- * The #UDisksLinuxDrive structure contains only private data and
- * should only be accessed using the provided API.
+ * The #UDisksLinuxDrive structure contains only private data and should
+ * only be accessed using the provided API.
*/
struct _UDisksLinuxDrive
{
- UDisksObjectSkeleton parent_instance;
-
- UDisksDaemon *daemon;
-
- /* list of GUdevDevice objects for block objects */
- GList *devices;
-
- /* interfaces */
- UDisksDrive *iface_drive;
- UDisksDriveAta *iface_drive_ata;
-
- /* ATA Smart */
- guint64 ata_smart_updated;
- gboolean ata_smart_failing;
- gdouble ata_smart_temperature;
- guint64 ata_smart_power_on_seconds;
-
- guint64 detection_time_at_construction;
+ UDisksDriveSkeleton parent_instance;
};
-G_LOCK_DEFINE_STATIC (drive_lock);
-
struct _UDisksLinuxDriveClass
{
- UDisksObjectSkeletonClass parent_class;
-};
-
-enum
-{
- PROP_0,
- PROP_DAEMON,
- PROP_DEVICE
+ UDisksDriveSkeletonClass parent_class;
};
-G_DEFINE_TYPE (UDisksLinuxDrive, udisks_linux_drive, UDISKS_TYPE_OBJECT_SKELETON);
-
-static void
-udisks_linux_drive_finalize (GObject *object)
-{
- UDisksLinuxDrive *drive = UDISKS_LINUX_DRIVE (object);
-
- /* note: we don't hold a ref to drive->daemon or drive->mount_monitor */
- g_list_foreach (drive->devices, (GFunc) g_object_unref, NULL);
- g_list_free (drive->devices);
-
- if (drive->iface_drive != NULL)
- g_object_unref (drive->iface_drive);
- if (drive->iface_drive_ata != NULL)
- g_object_unref (drive->iface_drive_ata);
-
- if (G_OBJECT_CLASS (udisks_linux_drive_parent_class)->finalize != NULL)
- G_OBJECT_CLASS (udisks_linux_drive_parent_class)->finalize (object);
-}
-
-static void
-udisks_linux_drive_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- UDisksLinuxDrive *drive = UDISKS_LINUX_DRIVE (object);
-
- switch (prop_id)
- {
- case PROP_DAEMON:
- g_value_set_object (value, udisks_linux_drive_get_daemon (drive));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-udisks_linux_drive_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- UDisksLinuxDrive *drive = UDISKS_LINUX_DRIVE (object);
-
- switch (prop_id)
- {
- case PROP_DAEMON:
- g_assert (drive->daemon == NULL);
- /* we don't take a reference to the daemon */
- drive->daemon = g_value_get_object (value);
- break;
+static void drive_iface_init (UDisksDriveIface *iface);
- case PROP_DEVICE:
- g_assert (drive->devices == NULL);
- drive->devices = g_list_prepend (NULL, g_value_dup_object (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
+G_DEFINE_TYPE_WITH_CODE (UDisksLinuxDrive, udisks_linux_drive, UDISKS_TYPE_DRIVE_SKELETON,
+ G_IMPLEMENT_INTERFACE (UDISKS_TYPE_DRIVE, drive_iface_init));
+/* ---------------------------------------------------------------------------------------------------- */
static void
udisks_linux_drive_init (UDisksLinuxDrive *drive)
{
-}
-
-static GObjectConstructParam *
-find_construct_property (guint n_construct_properties,
- GObjectConstructParam *construct_properties,
- const gchar *name)
-{
- guint n;
- for (n = 0; n < n_construct_properties; n++)
- if (g_strcmp0 (g_param_spec_get_name (construct_properties[n].pspec), name) == 0)
- return &construct_properties[n];
- return NULL;
-}
-
-/* unless given, compute object path from sysfs path */
-static GObject *
-udisks_linux_drive_constructor (GType type,
- guint n_construct_properties,
- GObjectConstructParam *construct_properties)
-{
- GObjectConstructParam *cp;
- UDisksDaemon *daemon;
- GUdevClient *client;
- GUdevDevice *device;
-
- cp = find_construct_property (n_construct_properties, construct_properties, "daemon");
- g_assert (cp != NULL);
- daemon = UDISKS_DAEMON (g_value_get_object (cp->value));
- g_assert (daemon != NULL);
-
- client = udisks_linux_provider_get_udev_client (udisks_daemon_get_linux_provider (daemon));
-
- cp = find_construct_property (n_construct_properties, construct_properties, "device");
- g_assert (cp != NULL);
- device = G_UDEV_DEVICE (g_value_get_object (cp->value));
- g_assert (device != NULL);
-
- if (!udisks_linux_drive_should_include_device (client, device, NULL))
- {
- return NULL;
- }
- else
- {
- return G_OBJECT_CLASS (udisks_linux_drive_parent_class)->constructor (type,
- n_construct_properties,
- construct_properties);
- }
-}
-
-static void
-strip_and_replace_with_uscore (gchar *s)
-{
- guint n;
-
- if (s == NULL)
- goto out;
-
- g_strstrip (s);
-
- for (n = 0; s != NULL && s[n] != '\0'; n++)
- {
- if (s[n] == ' ' || s[n] == '-')
- s[n] = '_';
- }
-
- out:
- ;
-}
-
-static void
-udisks_linux_drive_constructed (GObject *object)
-{
- UDisksLinuxDrive *drive = UDISKS_LINUX_DRIVE (object);
- gchar *vendor;
- gchar *model;
- gchar *serial;
- GString *str;
-
- /* initial coldplug */
- udisks_linux_drive_uevent (drive, "add", drive->devices->data);
-
- /* compute the object path */
- vendor = g_strdup (udisks_drive_get_vendor (drive->iface_drive));
- model = g_strdup (udisks_drive_get_model (drive->iface_drive));
- serial = g_strdup (udisks_drive_get_serial (drive->iface_drive));
- strip_and_replace_with_uscore (vendor);
- strip_and_replace_with_uscore (model);
- strip_and_replace_with_uscore (serial);
- str = g_string_new ("/org/freedesktop/UDisks2/drives/");
- if (vendor == NULL && model == NULL && serial == NULL)
- {
- g_string_append (str, "drive");
- }
- else
- {
- /* <VENDOR>_<MODEL>_<SERIAL> */
- if (vendor != NULL && strlen (vendor) > 0)
- {
- udisks_safe_append_to_object_path (str, vendor);
- }
- if (model != NULL && strlen (model) > 0)
- {
- if (str->str[str->len - 1] != '/')
- g_string_append_c (str, '_');
- udisks_safe_append_to_object_path (str, model);
- }
- if (serial != NULL && strlen (serial) > 0)
- {
- if (str->str[str->len - 1] != '/')
- g_string_append_c (str, '_');
- udisks_safe_append_to_object_path (str, serial);
- }
- }
- g_free (vendor);
- g_free (model);
- g_free (serial);
- g_dbus_object_skeleton_set_object_path (G_DBUS_OBJECT_SKELETON (drive), str->str);
- g_string_free (str, TRUE);
-
- if (G_OBJECT_CLASS (udisks_linux_drive_parent_class)->constructed != NULL)
- G_OBJECT_CLASS (udisks_linux_drive_parent_class)->constructed (object);
+ g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (drive),
+ G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
}
static void
udisks_linux_drive_class_init (UDisksLinuxDriveClass *klass)
{
- GObjectClass *gobject_class;
-
- gobject_class = G_OBJECT_CLASS (klass);
- gobject_class->constructor = udisks_linux_drive_constructor;
- gobject_class->finalize = udisks_linux_drive_finalize;
- gobject_class->constructed = udisks_linux_drive_constructed;
- gobject_class->set_property = udisks_linux_drive_set_property;
- gobject_class->get_property = udisks_linux_drive_get_property;
-
- /**
- * UDisksLinuxDrive:daemon:
- *
- * The #UDisksDaemon the object is for.
- */
- g_object_class_install_property (gobject_class,
- PROP_DAEMON,
- g_param_spec_object ("daemon",
- "Daemon",
- "The daemon the object is for",
- UDISKS_TYPE_DAEMON,
- G_PARAM_READABLE |
- G_PARAM_WRITABLE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS));
-
- /**
- * UDisksLinuxDrive:device:
- *
- * The #GUdevDevice for the object. Connect to the #GObject::notify
- * signal to get notified whenever this is updated.
- */
- g_object_class_install_property (gobject_class,
- PROP_DEVICE,
- g_param_spec_object ("device",
- "Device",
- "The device for the object",
- G_UDEV_TYPE_DEVICE,
- G_PARAM_WRITABLE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS));
-
}
/**
* udisks_linux_drive_new:
- * @daemon: A #UDisksDaemon.
- * @device: The #GUdevDevice for the sysfs block device.
- *
- * Create a new drive object.
- *
- * Returns: A #UDisksLinuxDrive object or %NULL if @device does not represent a drive. Free with g_object_unref().
- */
-UDisksLinuxDrive *
-udisks_linux_drive_new (UDisksDaemon *daemon,
- GUdevDevice *device)
-{
- GObject *object;
-
- g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
-
- object = g_object_new (UDISKS_TYPE_LINUX_DRIVE,
- "daemon", daemon,
- "device", device,
- NULL);
-
- if (object != NULL)
- return UDISKS_LINUX_DRIVE (object);
- else
- return NULL;
-}
-
-/**
- * udisks_linux_drive_get_daemon:
- * @drive: A #UDisksLinuxDrive.
- *
- * Gets the daemon used by @drive.
*
- * Returns: A #UDisksDaemon. Do not free, the object is owned by @drive.
- */
-UDisksDaemon *
-udisks_linux_drive_get_daemon (UDisksLinuxDrive *drive)
-{
- g_return_val_if_fail (UDISKS_IS_LINUX_DRIVE (drive), NULL);
- return drive->daemon;
-}
-
-/**
- * udisks_linux_drive_get_devices:
- * @drive: A #UDisksLinuxDrive.
- *
- * Gets the current #GUdevDevice objects associated with @drive.
+ * Creates a new #UDisksLinuxDrive instance.
*
- * Returns: A list of #GUdevDevice objects. Free each element with
- * g_object_unref(), then free the list with g_list_free().
+ * Returns: A new #UDisksLinuxDrive. Free with g_object_unref().
*/
-GList *
-udisks_linux_drive_get_devices (UDisksLinuxDrive *drive)
-{
- GList *ret;
- g_return_val_if_fail (UDISKS_IS_LINUX_DRIVE (drive), NULL);
- ret = g_list_copy (drive->devices);
- g_list_foreach (ret, (GFunc) g_object_ref, NULL);
- return ret;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-typedef gboolean (*HasInterfaceFunc) (UDisksLinuxDrive *drive);
-typedef void (*ConnectInterfaceFunc) (UDisksLinuxDrive *drive);
-typedef void (*UpdateInterfaceFunc) (UDisksLinuxDrive *drive,
- const gchar *uevent_action,
- GDBusInterface *interface);
-
-static void
-update_iface (UDisksLinuxDrive *drive,
- const gchar *uevent_action,
- HasInterfaceFunc has_func,
- ConnectInterfaceFunc connect_func,
- UpdateInterfaceFunc update_func,
- GType skeleton_type,
- gpointer _interface_pointer)
+UDisksDrive *
+udisks_linux_drive_new (void)
{
- gboolean has;
- gboolean add;
- GDBusInterface **interface_pointer = _interface_pointer;
-
- g_return_if_fail (drive != NULL);
- g_return_if_fail (has_func != NULL);
- g_return_if_fail (update_func != NULL);
- g_return_if_fail (g_type_is_a (skeleton_type, G_TYPE_OBJECT));
- g_return_if_fail (g_type_is_a (skeleton_type, G_TYPE_DBUS_INTERFACE));
- g_return_if_fail (interface_pointer != NULL);
- g_return_if_fail (*interface_pointer == NULL || G_IS_DBUS_INTERFACE (*interface_pointer));
-
- add = FALSE;
- has = has_func (drive);
- if (*interface_pointer == NULL)
- {
- if (has)
- {
- *interface_pointer = g_object_new (skeleton_type, NULL);
- if (connect_func != NULL)
- connect_func (drive);
- add = TRUE;
- }
- }
- else
- {
- if (!has)
- {
- g_dbus_object_skeleton_remove_interface (G_DBUS_OBJECT_SKELETON (drive), G_DBUS_INTERFACE_SKELETON (*interface_pointer));
- g_object_unref (*interface_pointer);
- *interface_pointer = NULL;
- }
- }
-
- if (*interface_pointer != NULL)
- {
- update_func (drive, uevent_action, G_DBUS_INTERFACE (*interface_pointer));
- if (add)
- g_dbus_object_skeleton_add_interface (G_DBUS_OBJECT_SKELETON (drive), G_DBUS_INTERFACE_SKELETON (*interface_pointer));
- }
+ return UDISKS_DRIVE (g_object_new (UDISKS_TYPE_LINUX_DRIVE,
+ NULL));
}
/* ---------------------------------------------------------------------------------------------------- */
-/* org.freedesktop.UDisks.Drive */
static const struct
{
@@ -539,9 +190,8 @@ ptr_str_array_compare (const gchar **a,
}
static void
-drive_set_media (UDisksLinuxDrive *drive,
- UDisksDrive *iface,
- GUdevDevice *device)
+set_media (UDisksDrive *iface,
+ GUdevDevice *device)
{
guint n;
GPtrArray *media_compat_array;
@@ -581,9 +231,8 @@ drive_set_media (UDisksLinuxDrive *drive,
}
static void
-drive_set_rotation_rate (UDisksLinuxDrive *drive,
- UDisksDrive *iface,
- GUdevDevice *device)
+set_rotation_rate (UDisksDrive *iface,
+ GUdevDevice *device)
{
gint rate;
@@ -600,144 +249,9 @@ drive_set_rotation_rate (UDisksLinuxDrive *drive,
udisks_drive_set_rotation_rate (iface, rate);
}
-static gboolean
-drive_check (UDisksLinuxDrive *drive)
-{
- return TRUE;
-}
-
-/* TODO: ensure that returned object is for a physical device e.g. not multipath */
-static UDisksObject *
-find_block_object (UDisksLinuxDrive *drive)
-{
- GDBusObjectManagerServer *object_manager;
- UDisksObject *ret;
- GList *objects;
- GList *l;
-
- ret = NULL;
-
- object_manager = udisks_daemon_get_object_manager (udisks_linux_drive_get_daemon (drive));
- objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (object_manager));
- for (l = objects; l != NULL; l = l->next)
- {
- GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (l->data);
- UDisksBlockDevice *block;
- GUdevDevice *device;
- gboolean is_disk;
-
- if (!UDISKS_IS_LINUX_BLOCK (object))
- continue;
-
- device = udisks_linux_block_get_device (UDISKS_LINUX_BLOCK (object));
- is_disk = (g_strcmp0 (g_udev_device_get_devtype (device), "disk") == 0);
- g_object_unref (device);
-
- if (!is_disk)
- continue;
-
- block = udisks_object_peek_block_device (UDISKS_OBJECT (object));
-
- if (g_strcmp0 (udisks_block_device_get_drive (block),
- g_dbus_object_get_object_path (G_DBUS_OBJECT (drive))) == 0)
- {
- ret = g_object_ref (object);
- goto out;
- }
- }
-
- out:
- g_list_foreach (objects, (GFunc) g_object_unref, NULL);
- g_list_free (objects);
- return ret;
-}
-
-static gboolean
-on_eject (UDisksDrive *drive_iface,
- GDBusMethodInvocation *invocation,
- GVariant *options,
- gpointer user_data)
-{
- UDisksLinuxDrive *drive = UDISKS_LINUX_DRIVE (user_data);
- UDisksObject *block_object;
- UDisksBlockDevice *block;
- UDisksDaemon *daemon;
- const gchar *action_id;
- gchar *error_message;
-
- daemon = NULL;
- block = NULL;
- error_message = NULL;
-
- daemon = udisks_linux_drive_get_daemon (drive);
- block_object = find_block_object (drive);
- if (block_object == NULL)
- {
- g_dbus_method_invocation_return_error (invocation,
- UDISKS_ERROR,
- UDISKS_ERROR_FAILED,
- "Unable to find physical block device for drive");
- goto out;
- }
- block = udisks_object_peek_block_device (block_object);
-
- /* TODO: is it a good idea to overload modify-device? */
- action_id = "org.freedesktop.udisks2.modify-device";
- if (udisks_block_device_get_hint_system (block))
- action_id = "org.freedesktop.udisks2.modify-device-system";
-
- /* Check that the user is actually authorized */
- if (!udisks_daemon_util_check_authorization_sync (daemon,
- block_object,
- action_id,
- options,
- N_("Authentication is required to eject $(udisks2.device)"),
- invocation))
- goto out;
-
- if (!udisks_daemon_launch_spawned_job_sync (daemon,
- NULL, /* GCancellable */
- 0, /* uid_t run_as_uid */
- 0, /* uid_t run_as_euid */
- NULL, /* gint *out_status */
- &error_message,
- NULL, /* input_string */
- "eject \"%s\"",
- udisks_block_device_get_device (block)))
- {
- g_dbus_method_invocation_return_error (invocation,
- UDISKS_ERROR,
- UDISKS_ERROR_FAILED,
- "Error eject %s: %s",
- udisks_block_device_get_device (block),
- error_message);
- goto out;
- }
-
- udisks_drive_complete_eject (drive_iface, invocation);
-
- out:
- if (block_object != NULL)
- g_object_unref (block_object);
- g_free (error_message);
- return TRUE; /* returning TRUE means that we handled the method invocation */
-}
-
-static void
-drive_connect (UDisksLinuxDrive *drive)
-{
- g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (drive->iface_drive),
- G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
- g_signal_connect (drive->iface_drive,
- "handle-eject",
- G_CALLBACK (on_eject),
- drive);
-}
-
static void
-drive_set_connection_bus (UDisksLinuxDrive *drive,
- UDisksDrive *iface,
- GUdevDevice *device)
+set_connection_bus (UDisksDrive *iface,
+ GUdevDevice *device)
{
GUdevDevice *parent;
@@ -767,20 +281,25 @@ drive_set_connection_bus (UDisksLinuxDrive *drive,
}
-static void
-drive_update (UDisksLinuxDrive *drive,
- const gchar *uevent_action,
- GDBusInterface *_iface)
+/**
+ * udisks_linux_drive_update:
+ * @drive: A #UDisksLinuxDrive.
+ * @object: The enclosing #UDisksLinuxDriveObject instance.
+ *
+ * Updates the interface.
+ */
+void
+udisks_linux_drive_update (UDisksLinuxDrive *drive,
+ UDisksLinuxDriveObject *object)
{
- UDisksDrive *iface = UDISKS_DRIVE (_iface);
+ UDisksDrive *iface = UDISKS_DRIVE (drive);
GUdevDevice *device;
gchar *sort_key;
- if (drive->devices == NULL)
+ device = udisks_linux_drive_object_get_device (object, TRUE /* get_hw */);
+ if (device == NULL)
goto out;
- device = G_UDEV_DEVICE (drive->devices->data);
-
/* this is the _almost_ the same for both ATA and SCSI devices (cf. udev's ata_id and scsi_id)
* but we special case since there are subtle differences...
*/
@@ -916,9 +435,9 @@ drive_update (UDisksLinuxDrive *drive,
/* common bits go here */
udisks_drive_set_media_removable (iface, g_udev_device_get_sysfs_attr_as_boolean (device, "removable"));
udisks_drive_set_size (iface, udisks_daemon_util_block_get_size (device));
- drive_set_media (drive, iface, device);
- drive_set_rotation_rate (drive, iface, device);
- drive_set_connection_bus (drive, iface, device);
+ set_media (iface, device);
+ set_rotation_rate (iface, device);
+ set_connection_bus (iface, device);
#if 0
/* This ensures that devices are shown in the order they are detected */
@@ -931,129 +450,43 @@ drive_update (UDisksLinuxDrive *drive,
{
GUdevClient *client;
GUdevDevice *ns_device;
- client = udisks_linux_provider_get_udev_client (udisks_daemon_get_linux_provider (drive->daemon));
+ client = g_udev_client_new (NULL);
ns_device = g_udev_client_query_by_sysfs_path (client, g_udev_device_get_sysfs_path (device));
sort_key = g_strdup_printf ("%" G_GUINT64_FORMAT,
time (NULL) * G_USEC_PER_SEC - g_udev_device_get_usec_since_initialized (ns_device));
g_object_unref (ns_device);
+ g_object_unref (client);
}
#endif
udisks_drive_set_sort_key (iface, sort_key);
g_free (sort_key);
out:
- ;
+ if (device != NULL)
+ g_object_unref (device);
}
/* ---------------------------------------------------------------------------------------------------- */
-static void drive_ata_smart_update (UDisksLinuxDrive *drive);
-
-static gboolean
-update_smart (UDisksLinuxDrive *drive,
- gboolean nowakeup,
- GError **error)
-{
- gboolean ret;
- SkDisk *d;
- SkBool awake;
- SkBool good;
- uint64_t temp_mkelvin;
- uint64_t power_on_msec;
- GUdevDevice *device;
-
- d = NULL;
- ret = FALSE;
-
- device = G_UDEV_DEVICE (drive->devices->data);
-
- if (sk_disk_open (g_udev_device_get_device_file (device), &d) != 0)
- {
- g_set_error (error,
- UDISKS_ERROR,
- UDISKS_ERROR_FAILED,
- "sk_disk_open: %m");
- goto out;
- }
-
- if (sk_disk_check_sleep_mode (d, &awake) != 0)
- {
- g_set_error (error,
- UDISKS_ERROR,
- UDISKS_ERROR_FAILED,
- "sk_disk_check_sleep_mode: %m");
- goto out;
- }
-
- /* don't wake up disk unless specically asked to */
- if (nowakeup && !awake)
- {
- g_set_error (error,
- UDISKS_ERROR,
- UDISKS_ERROR_WOULD_WAKEUP,
- "Disk is in sleep mode and the nowakeup option was passed");
- goto out;
- }
-
- if (sk_disk_smart_read_data (d) != 0)
- {
- g_set_error (error,
- UDISKS_ERROR,
- UDISKS_ERROR_FAILED,
- "sk_disk_smart_read_data: %m");
- goto out;
- }
-
- if (sk_disk_smart_status (d, &good) != 0)
- {
- g_set_error (error,
- UDISKS_ERROR,
- UDISKS_ERROR_FAILED,
- "sk_disk_smart_status: %m");
- goto out;
- }
-
- /* don't care if these are failing or not */
- temp_mkelvin = 0;
- sk_disk_smart_get_temperature (d, &temp_mkelvin);
- power_on_msec = 0;
- sk_disk_smart_get_power_on (d, &power_on_msec);
-
- G_LOCK (drive_lock);
- drive->ata_smart_updated = time (NULL);
- drive->ata_smart_failing = !good;
- drive->ata_smart_temperature = temp_mkelvin / 1000.0;
- drive->ata_smart_power_on_seconds = power_on_msec / 1000.0;
- G_UNLOCK (drive_lock);
-
- drive_ata_smart_update (drive);
-
- ret = TRUE;
-
- out:
- if (d != NULL)
- sk_disk_free (d);
- return ret;
-}
-
static gboolean
-on_smart_update (UDisksDriveAta *drive_ata_iface,
- GDBusMethodInvocation *invocation,
- GVariant *options,
- gpointer user_data)
+handle_eject (UDisksDrive *_drive,
+ GDBusMethodInvocation *invocation,
+ GVariant *options)
{
- UDisksLinuxDrive *drive = UDISKS_LINUX_DRIVE (user_data);
- UDisksObject *block_object;
+ UDisksLinuxDrive *drive = UDISKS_LINUX_DRIVE (_drive);
+ UDisksLinuxDriveObject *object;
+ UDisksLinuxBlock *block_object;
UDisksBlockDevice *block;
UDisksDaemon *daemon;
const gchar *action_id;
- gboolean nowakeup;
- GError *error;
+ gchar *error_message;
daemon = NULL;
block = NULL;
+ error_message = NULL;
- daemon = udisks_linux_drive_get_daemon (drive);
- block_object = find_block_object (drive);
+ object = UDISKS_LINUX_DRIVE_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (drive)));
+ daemon = udisks_linux_drive_object_get_daemon (object);
+ block_object = udisks_linux_drive_object_get_block (object, TRUE);
if (block_object == NULL)
{
g_dbus_method_invocation_return_error (invocation,
@@ -1062,12 +495,7 @@ on_smart_update (UDisksDriveAta *drive_ata_iface,
"Unable to find physical block device for drive");
goto out;
}
- block = udisks_object_peek_block_device (block_object);
-
- g_variant_lookup (options,
- "nowakeup",
- "b",
- &nowakeup);
+ block = udisks_object_peek_block_device (UDISKS_OBJECT (block_object));
/* TODO: is it a good idea to overload modify-device? */
action_id = "org.freedesktop.udisks2.modify-device";
@@ -1076,396 +504,45 @@ on_smart_update (UDisksDriveAta *drive_ata_iface,
/* Check that the user is actually authorized */
if (!udisks_daemon_util_check_authorization_sync (daemon,
- block_object,
+ UDISKS_OBJECT (block_object),
action_id,
options,
- N_("Authentication is required to update SMART from $(udisks2.device)"),
+ N_("Authentication is required to eject $(udisks2.device)"),
invocation))
goto out;
- if (!udisks_drive_ata_get_smart_supported (drive_ata_iface))
- {
- g_dbus_method_invocation_return_error (invocation,
- UDISKS_ERROR,
- UDISKS_ERROR_FAILED,
- "SMART is not supported");
- goto out;
- }
-
- if (!udisks_drive_ata_get_smart_enabled (drive_ata_iface))
+ if (!udisks_daemon_launch_spawned_job_sync (daemon,
+ NULL, /* GCancellable */
+ 0, /* uid_t run_as_uid */
+ 0, /* uid_t run_as_euid */
+ NULL, /* gint *out_status */
+ &error_message,
+ NULL, /* input_string */
+ "eject \"%s\"",
+ udisks_block_device_get_device (block)))
{
g_dbus_method_invocation_return_error (invocation,
UDISKS_ERROR,
UDISKS_ERROR_FAILED,
- "SMART is not enabled");
- goto out;
- }
-
- error = NULL;
- if (!update_smart (drive, nowakeup, &error))
- {
- udisks_warning ("Error updating ATA smart for %s: %s (%s, %d)",
- g_dbus_object_get_object_path (G_DBUS_OBJECT (drive)),
- error->message, g_quark_to_string (error->domain), error->code);
- g_dbus_method_invocation_take_error (invocation, error);
+ "Error eject %s: %s",
+ udisks_block_device_get_device (block),
+ error_message);
goto out;
}
- udisks_drive_ata_complete_smart_update (drive_ata_iface, invocation);
+ udisks_drive_complete_eject (UDISKS_DRIVE (drive), invocation);
out:
if (block_object != NULL)
g_object_unref (block_object);
+ g_free (error_message);
return TRUE; /* returning TRUE means that we handled the method invocation */
}
-static gboolean
-drive_ata_check (UDisksLinuxDrive *drive)
-{
- gboolean ret;
- GUdevDevice *device;
-
- ret = FALSE;
- if (drive->devices == NULL)
- goto out;
-
- device = G_UDEV_DEVICE (drive->devices->data);
- if (!g_udev_device_get_property_as_boolean (device, "ID_ATA"))
- goto out;
-
- ret = TRUE;
-
- out:
- return ret;
-}
-
-static void
-drive_ata_connect (UDisksLinuxDrive *drive)
-{
- g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (drive->iface_drive_ata),
- G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
- g_signal_connect (drive->iface_drive_ata,
- "handle-smart-update",
- G_CALLBACK (on_smart_update),
- drive);
-}
-
-/* also called from *any* thread when the SMART data has been updated */
-static void
-drive_ata_smart_update (UDisksLinuxDrive *drive)
-{
- GUdevDevice *device;
- gboolean supported;
- gboolean enabled;
- guint64 updated;
- gboolean failing;
- gdouble temperature;
- guint64 power_on_seconds;
-
- device = G_UDEV_DEVICE (drive->devices->data);
-
- supported = g_udev_device_get_property_as_boolean (device, "ID_ATA_FEATURE_SET_SMART");
- enabled = g_udev_device_get_property_as_boolean (device, "ID_ATA_FEATURE_SET_SMART_ENABLED");
- updated = 0;
- failing = FALSE;
- temperature = 0.0;
- power_on_seconds = 0;
-
- G_LOCK (drive_lock);
- if (drive->ata_smart_updated > 0)
- {
- updated = drive->ata_smart_updated;
- failing = drive->ata_smart_failing;
- temperature = drive->ata_smart_temperature;
- power_on_seconds = drive->ata_smart_power_on_seconds;
- }
- G_UNLOCK (drive_lock);
-
- g_object_freeze_notify (G_OBJECT (drive->iface_drive_ata));
- udisks_drive_ata_set_smart_supported (drive->iface_drive_ata, supported);
- udisks_drive_ata_set_smart_enabled (drive->iface_drive_ata, enabled);
- udisks_drive_ata_set_smart_updated (drive->iface_drive_ata, updated);
- udisks_drive_ata_set_smart_failing (drive->iface_drive_ata, failing);
- udisks_drive_ata_set_smart_temperature (drive->iface_drive_ata, temperature);
- udisks_drive_ata_set_smart_power_on_seconds (drive->iface_drive_ata, power_on_seconds);
- g_object_thaw_notify (G_OBJECT (drive->iface_drive_ata));
-}
-
-static void
-drive_ata_update (UDisksLinuxDrive *drive,
- const gchar *uevent_action,
- GDBusInterface *_iface)
-{
- drive_ata_smart_update (drive);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static GList *
-find_link_for_sysfs_path (UDisksLinuxDrive *drive,
- const gchar *sysfs_path)
-{
- GList *l;
- GList *ret;
- ret = NULL;
- for (l = drive->devices; l != NULL; l = l->next)
- {
- GUdevDevice *device = G_UDEV_DEVICE (l->data);
- if (g_strcmp0 (g_udev_device_get_sysfs_path (device), sysfs_path) == 0)
- {
- ret = l;
- goto out;
- }
- }
- out:
- return ret;
-}
-
-/**
- * udisks_linux_drive_uevent:
- * @drive: A #UDisksLinuxDrive.
- * @action: Uevent action or %NULL
- * @device: A new #GUdevDevice device object or %NULL if the device hasn't changed.
- *
- * Updates all information on interfaces on @drive.
- */
-void
-udisks_linux_drive_uevent (UDisksLinuxDrive *drive,
- const gchar *action,
- GUdevDevice *device)
-{
- GList *link;
-
- g_return_if_fail (UDISKS_IS_LINUX_DRIVE (drive));
- g_return_if_fail (G_UDEV_IS_DEVICE (device));
-
- link = find_link_for_sysfs_path (drive, g_udev_device_get_sysfs_path (device));
- if (g_strcmp0 (action, "remove") == 0)
- {
- if (link != NULL)
- {
- g_object_unref (G_UDEV_DEVICE (link->data));
- drive->devices = g_list_delete_link (drive->devices, link);
- }
- else
- {
- udisks_warning ("Drive doesn't have device with sysfs path %s on remove event",
- g_udev_device_get_sysfs_path (device));
- }
- }
- else
- {
- if (link != NULL)
- {
- g_object_unref (G_UDEV_DEVICE (link->data));
- link->data = g_object_ref (device);
- }
- else
- {
- drive->devices = g_list_append (drive->devices, g_object_ref (device));
- }
- }
-
- update_iface (drive, action, drive_check, drive_connect, drive_update,
- UDISKS_TYPE_DRIVE_SKELETON, &drive->iface_drive);
- update_iface (drive, action, drive_ata_check, drive_ata_connect, drive_ata_update,
- UDISKS_TYPE_DRIVE_ATA_SKELETON, &drive->iface_drive_ata);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gchar *
-check_for_vpd (GUdevDevice *device)
-{
- gchar *ret;
- const gchar *serial;
- const gchar *wwn;
-
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
-
- ret = NULL;
-
- /* prefer WWN to serial */
- serial = g_udev_device_get_property (device, "ID_SERIAL");
- wwn = g_udev_device_get_property (device, "ID_WWN_WITH_EXTENSION");
- if (wwn != NULL && strlen (wwn) > 0)
- {
- ret = g_strdup (wwn);
- }
- else if (serial != NULL && strlen (serial) > 0)
- {
- ret = g_strdup (serial);
- }
- return ret;
-}
-
-/* <internal>
- * udisks_linux_drive_should_include_device:
- * @client: A #GUdevClient.
- * @device: A #GUdevDevice.
- * @out_vpd: Return location for unique ID or %NULL.
- *
- * Checks if we should even construct a #UDisksLinuxDrive for @device.
- *
- * Returns: %TRUE if we should construct an object, %FALSE otherwise.
- */
-gboolean
-udisks_linux_drive_should_include_device (GUdevClient *client,
- GUdevDevice *device,
- gchar **out_vpd)
-{
- gboolean ret;
- gchar *vpd;
-
- ret = FALSE;
- vpd = NULL;
-
- /* The 'block' subsystem encompasses several objects with varying
- * DEVTYPE including
- *
- * - disk
- * - partition
- *
- * and we are only interested in the first.
- */
- if (g_strcmp0 (g_udev_device_get_devtype (device), "disk") != 0)
- goto out;
-
- vpd = check_for_vpd (device);
-
- if (vpd == NULL)
- {
- const gchar *name;
- GUdevDevice *parent;
-
- name = g_udev_device_get_name (device);
-
- /* workaround for missing serial/wwn on virtio-blk */
- if (g_str_has_prefix (name, "vd"))
- {
- vpd = g_strdup (name);
- goto found;
- }
-
- /* workaround for missing serial/wwn on firewire devices */
- parent = g_udev_device_get_parent_with_subsystem (device, "firewire", NULL);
- if (parent != NULL)
- {
- vpd = g_strdup (name);
- g_object_unref (parent);
- goto found;
- }
-
- /* dm-multipath */
- const gchar *dm_name;
- dm_name = g_udev_device_get_sysfs_attr (device, "dm/name");
- if (dm_name != NULL && g_str_has_prefix (dm_name, "mpath"))
- {
- gchar **slaves;
- guint n;
- slaves = udisks_daemon_util_resolve_links (g_udev_device_get_sysfs_path (device), "slaves");
- for (n = 0; slaves[n] != NULL; n++)
- {
- GUdevDevice *slave;
- slave = g_udev_client_query_by_sysfs_path (client, slaves[n]);
- if (slave != NULL)
- {
- vpd = check_for_vpd (slave);
- if (vpd != NULL)
- {
- g_object_unref (slave);
- g_strfreev (slaves);
- goto found;
- }
- g_object_unref (slave);
- }
- }
- g_strfreev (slaves);
- }
- }
-
- found:
- if (vpd != NULL)
- {
- if (out_vpd != NULL)
- {
- *out_vpd = vpd;
- vpd = NULL;
- }
- ret = TRUE;
- }
-
- out:
- g_free (vpd);
- return ret;
-}
-
/* ---------------------------------------------------------------------------------------------------- */
-/**
- * udisks_linux_drive_housekeeping:
- * @drive: A #UDisksLinuxDrive.
- * @secs_since_last: Number of seconds sincex the last housekeeping or 0 if the first housekeeping ever.
- * @cancellable: A %GCancellable or %NULL.
- * @error: Return location for error or %NULL.
- *
- * Called periodically (every ten minutes or so) to perform
- * housekeeping tasks such as refreshing ATA SMART data.
- *
- * The function runs in a dedicated thread and is allowed to perform
- * blocking I/O.
- *
- * Long-running tasks should periodically check @cancellable to see if
- * they have been cancelled.
- *
- * Returns: %TRUE if the operation succeeded, %FALSE if @error is set.
- */
-gboolean
-udisks_linux_drive_housekeeping (UDisksLinuxDrive *drive,
- guint secs_since_last,
- GCancellable *cancellable,
- GError **error)
+static void
+drive_iface_init (UDisksDriveIface *iface)
{
- gboolean ret;
-
- ret = FALSE;
-
- if (drive->iface_drive_ata != NULL &&
- udisks_drive_ata_get_smart_supported (drive->iface_drive_ata) &&
- udisks_drive_ata_get_smart_enabled (drive->iface_drive_ata))
- {
- GError *local_error;
- gboolean nowakeup;
-
- /* Wake-up only on start-up */
- nowakeup = TRUE;
- if (secs_since_last == 0)
- nowakeup = FALSE;
-
- udisks_info ("Refreshing SMART data on %s (nowakeup=%d)",
- g_dbus_object_get_object_path (G_DBUS_OBJECT (drive)),
- nowakeup);
-
- local_error = NULL;
- if (!update_smart (drive, nowakeup, &local_error))
- {
- if (nowakeup && (local_error->domain == UDISKS_ERROR &&
- local_error->code == UDISKS_ERROR_WOULD_WAKEUP))
- {
- udisks_info ("Drive %s is in a sleep state",
- g_dbus_object_get_object_path (G_DBUS_OBJECT (drive)));
- g_error_free (local_error);
- }
- else
- {
- g_propagate_prefixed_error (error, local_error, "Error updating SMART data: ");
- goto out;
- }
- }
- }
-
- ret = TRUE;
-
- out:
- return ret;
+ iface->handle_eject = handle_eject;
}