From c4a9f24ac89e1a91199c4afae8ecda159ec1e10e Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Thu, 19 Feb 2009 19:36:47 -0500 Subject: [PATCH] poll for media, also add methods to inhibit polling and manual polling For this to work well, the polling that happens in HAL needs to be disabled. This can be achieved by this fdi file false There's also a TODO in the code to properly detect SATA AN drives and avoid polling these. --- policy/org.freedesktop.devicekit.disks.policy.in | 10 + src/Makefile.am | 2 + src/devkit-disks-daemon.c | 169 +++++++++++++++ src/devkit-disks-daemon.h | 12 ++ src/devkit-disks-device-private.h | 6 + src/devkit-disks-device.c | 219 +++++++++++++++++++ src/devkit-disks-device.h | 13 ++ src/devkit-disks-inhibitor.c | 157 ++++++++++++++ src/devkit-disks-inhibitor.h | 58 +++++ src/main.c | 8 +- src/org.freedesktop.DeviceKit.Disks.Device.xml | 107 ++++++++++ src/org.freedesktop.DeviceKit.Disks.xml | 62 ++++++ src/poller.c | 235 ++++++++++++++++++++ src/poller.h | 31 +++ tools/devkit-disks-bash-completion.sh | 4 +- tools/devkit-disks.c | 261 ++++++++++++++++------- 16 files changed, 1269 insertions(+), 85 deletions(-) create mode 100644 src/devkit-disks-inhibitor.c create mode 100644 src/devkit-disks-inhibitor.h create mode 100644 src/poller.c create mode 100644 src/poller.h diff --git a/policy/org.freedesktop.devicekit.disks.policy.in b/policy/org.freedesktop.devicekit.disks.policy.in index b8ce54b..a3f592e 100644 --- a/policy/org.freedesktop.devicekit.disks.policy.in +++ b/policy/org.freedesktop.devicekit.disks.policy.in @@ -240,4 +240,14 @@ file are instantly applied. + + <_description>Inhibit media detection + <_message>Authentication is required to inhibit media detection + + no + no + yes + + + diff --git a/src/Makefile.am b/src/Makefile.am index c30e525..9aee887 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -45,6 +45,8 @@ devkit_disks_daemon_SOURCES = \ devkit-disks-device-private.h \ mounts-file.h mounts-file.c \ devkit-disks-mount-monitor.h devkit-disks-mount-monitor.c \ + devkit-disks-inhibitor.h devkit-disks-inhibitor.c \ + poller.h poller.c \ main.c \ $(BUILT_SOURCES) diff --git a/src/devkit-disks-daemon.c b/src/devkit-disks-daemon.c index 13acdd4..17335ed 100644 --- a/src/devkit-disks-daemon.c +++ b/src/devkit-disks-daemon.c @@ -54,6 +54,8 @@ #include "devkit-disks-device-private.h" #include "mounts-file.h" #include "devkit-disks-mount-monitor.h" +#include "poller.h" +#include "devkit-disks-inhibitor.h" #include "devkit-disks-daemon-glue.h" #include "devkit-disks-marshal.h" @@ -99,12 +101,17 @@ struct DevkitDisksDaemonPrivate guint smart_refresh_timer_id; DevkitDisksLogger *logger; + + GList *polling_inhibitors; }; static void devkit_disks_daemon_class_init (DevkitDisksDaemonClass *klass); static void devkit_disks_daemon_init (DevkitDisksDaemon *seat); static void devkit_disks_daemon_finalize (GObject *object); +static void daemon_polling_inhibitor_disconnected_cb (DevkitDisksInhibitor *inhibitor, + DevkitDisksDaemon *daemon); + G_DEFINE_TYPE (DevkitDisksDaemon, devkit_disks_daemon, G_TYPE_OBJECT) #define DEVKIT_DISKS_DAEMON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DEVKIT_TYPE_DISKS_DAEMON, DevkitDisksDaemonPrivate)) @@ -563,6 +570,7 @@ static void devkit_disks_daemon_finalize (GObject *object) { DevkitDisksDaemon *daemon; + GList *l; g_return_if_fail (object != NULL); g_return_if_fail (DEVKIT_IS_DISKS_DAEMON (object)); @@ -610,6 +618,13 @@ devkit_disks_daemon_finalize (GObject *object) g_object_unref (daemon->priv->logger); } + for (l = daemon->priv->polling_inhibitors; l != NULL; l = l->next) { + DevkitDisksInhibitor *inhibitor = DEVKIT_DISKS_INHIBITOR (l->data); + g_signal_handlers_disconnect_by_func (inhibitor, daemon_polling_inhibitor_disconnected_cb, daemon); + g_object_unref (inhibitor); + } + g_list_free (daemon->priv->polling_inhibitors); + G_OBJECT_CLASS (devkit_disks_daemon_parent_class)->finalize (object); } @@ -647,6 +662,8 @@ pk_io_remove_watch (PolKitContext *pk_context, int watch_id) g_source_remove (watch_id); } +void devkit_disks_inhibitor_name_owner_changed (DBusMessage *message); + static DBusHandlerResult _filter (DBusConnection *connection, DBusMessage *message, void *user_data) { @@ -658,6 +675,9 @@ _filter (DBusConnection *connection, DBusMessage *message, void *user_data) if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) { /* pass NameOwnerChanged signals from the bus to PolKitTracker */ polkit_tracker_dbus_func (daemon->priv->pk_tracker, message); + + /* for now, pass NameOwnerChanged to DevkitDisksInhibitor */ + devkit_disks_inhibitor_name_owner_changed (message); } if (interface != NULL && g_str_has_prefix (interface, "org.freedesktop.ConsoleKit")) { @@ -718,6 +738,7 @@ device_changed (DevkitDisksDaemon *daemon, DevkitDevice *d, gboolean synthesized device_remove (daemon, d); } else { g_print ("changed %s\n", native_path); + devkit_disks_daemon_local_update_poller (daemon); } } else { g_print ("treating change event as add on %s\n", native_path); @@ -767,6 +788,7 @@ device_add (DevkitDisksDaemon *daemon, DevkitDevice *d, gboolean emit_event) object_path = devkit_disks_device_local_get_object_path (device); g_signal_emit (daemon, signals[DEVICE_ADDED_SIGNAL], 0, object_path); } + devkit_disks_daemon_local_update_poller (daemon); } else { g_print ("ignoring add event on %s\n", native_path); } @@ -788,6 +810,7 @@ device_remove (DevkitDisksDaemon *daemon, DevkitDevice *d) g_signal_emit (daemon, signals[DEVICE_REMOVED_SIGNAL], 0, devkit_disks_device_local_get_object_path (device)); g_object_unref (device); + devkit_disks_daemon_local_update_poller (daemon); } } @@ -1159,6 +1182,27 @@ devkit_disks_damon_local_check_auth (DevkitDisksDaemon *daemon, return ret; } +/*--------------------------------------------------------------------------------------------------------------*/ + +void +devkit_disks_daemon_local_update_poller (DevkitDisksDaemon *daemon) +{ + GHashTableIter hash_iter; + DevkitDisksDevice *device; + GList *devices_to_poll; + + devices_to_poll = NULL; + + g_hash_table_iter_init (&hash_iter, daemon->priv->map_object_path_to_device); + while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &device)) { + if (device->priv->info.device_is_media_change_detected) + devices_to_poll = g_list_prepend (devices_to_poll, device); + } + + poller_set_devices (devices_to_poll); + + g_list_free (devices_to_poll); +} /*--------------------------------------------------------------------------------------------------------------*/ @@ -1244,3 +1288,128 @@ out: } /*--------------------------------------------------------------------------------------------------------------*/ + +static void +polling_update_devices (DevkitDisksDaemon *daemon) +{ + GHashTableIter hash_iter; + DevkitDisksDevice *device; + + g_hash_table_iter_init (&hash_iter, daemon->priv->map_object_path_to_device); + while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &device)) { + + if (devkit_disks_device_local_update_media_detection (device)) { + DevkitDevice *d; + + d = g_object_ref (device->priv->d); + device_changed (daemon, d, TRUE); + g_object_unref (d); + } + } + + devkit_disks_daemon_local_update_poller (daemon); +} + +static void +daemon_polling_inhibitor_disconnected_cb (DevkitDisksInhibitor *inhibitor, + DevkitDisksDaemon *daemon) +{ + daemon->priv->polling_inhibitors = g_list_remove (daemon->priv->polling_inhibitors, inhibitor); + g_signal_handlers_disconnect_by_func (inhibitor, daemon_polling_inhibitor_disconnected_cb, daemon); + g_object_unref (inhibitor); + + polling_update_devices (daemon); +} + +gboolean +devkit_disks_daemon_local_has_polling_inhibitors (DevkitDisksDaemon *daemon) +{ + return daemon->priv->polling_inhibitors != NULL; +} + +gboolean +devkit_disks_daemon_drive_inhibit_all_polling (DevkitDisksDaemon *daemon, + char **options, + DBusGMethodInvocation *context) +{ + DevkitDisksInhibitor *inhibitor; + PolKitCaller *pk_caller; + guint n; + + if ((pk_caller = devkit_disks_damon_local_get_caller_for_context (daemon, context)) == NULL) + goto out; + + + if (!devkit_disks_damon_local_check_auth (daemon, + pk_caller, + "org.freedesktop.devicekit.disks.inhibit-polling", + context)) + goto out; + + for (n = 0; options[n] != NULL; n++) { + const char *option = options[n]; + throw_error (context, + DEVKIT_DISKS_ERROR_INVALID_OPTION, + "Unknown option %s", option); + goto out; + } + + inhibitor = devkit_disks_inhibitor_new (context); + + daemon->priv->polling_inhibitors = g_list_prepend (daemon->priv->polling_inhibitors, inhibitor); + g_signal_connect (inhibitor, "disconnected", G_CALLBACK (daemon_polling_inhibitor_disconnected_cb), daemon); + + polling_update_devices (daemon); + + dbus_g_method_return (context, devkit_disks_inhibitor_get_cookie (inhibitor)); + +out: + if (pk_caller != NULL) + polkit_caller_unref (pk_caller); + return TRUE; +} + + +/*--------------------------------------------------------------------------------------------------------------*/ + +gboolean +devkit_disks_daemon_drive_uninhibit_all_polling (DevkitDisksDaemon *daemon, + char *cookie, + DBusGMethodInvocation *context) +{ + const gchar *sender; + DevkitDisksInhibitor *inhibitor; + GList *l; + + sender = dbus_g_method_get_sender (context); + + inhibitor = NULL; + for (l = daemon->priv->polling_inhibitors; l != NULL; l = l->next) { + DevkitDisksInhibitor *i = DEVKIT_DISKS_INHIBITOR (l->data); + + if (g_strcmp0 (devkit_disks_inhibitor_get_unique_dbus_name (i), sender) == 0 && + g_strcmp0 (devkit_disks_inhibitor_get_cookie (i), cookie) == 0) { + inhibitor = i; + break; + } + } + + if (inhibitor == NULL) { + throw_error (context, + DEVKIT_DISKS_ERROR_FAILED, + "No such inhibitor"); + goto out; + } + + daemon->priv->polling_inhibitors = g_list_remove (daemon->priv->polling_inhibitors, inhibitor); + g_object_unref (inhibitor); + + polling_update_devices (daemon); + + dbus_g_method_return (context); + + out: + return TRUE; +} + +/*--------------------------------------------------------------------------------------------------------------*/ diff --git a/src/devkit-disks-daemon.h b/src/devkit-disks-daemon.h index 134f98f..fd66ef1 100644 --- a/src/devkit-disks-daemon.h +++ b/src/devkit-disks-daemon.h @@ -112,6 +112,10 @@ void devkit_disks_daemon_local_update_mount_state (DevkitDisksDae void devkit_disks_daemon_local_synthesize_changed (DevkitDisksDaemon *daemon, DevkitDevice *d); +void devkit_disks_daemon_local_update_poller (DevkitDisksDaemon *daemon); + +gboolean devkit_disks_daemon_local_has_polling_inhibitors (DevkitDisksDaemon *daemon); + DevkitDisksLogger *devkit_disks_daemon_local_get_logger (DevkitDisksDaemon *daemon); /* exported methods */ @@ -128,6 +132,14 @@ gboolean devkit_disks_daemon_linux_md_start (DevkitDisksDaemon *daemon, char **options, DBusGMethodInvocation *context); +gboolean devkit_disks_daemon_drive_inhibit_all_polling (DevkitDisksDaemon *daemon, + char **options, + DBusGMethodInvocation *context); + +gboolean devkit_disks_daemon_drive_uninhibit_all_polling (DevkitDisksDaemon *daemon, + char *cookie, + DBusGMethodInvocation *context); + G_END_DECLS #endif /* __DEVKIT_DISKS_DAEMON_H__ */ diff --git a/src/devkit-disks-device-private.h b/src/devkit-disks-device-private.h index 881b91f..11021bb 100644 --- a/src/devkit-disks-device-private.h +++ b/src/devkit-disks-device-private.h @@ -90,6 +90,9 @@ struct DevkitDisksDevicePrivate gboolean device_is_partition_table; gboolean device_is_removable; gboolean device_is_media_available; + gboolean device_is_media_change_detected; + gboolean device_is_media_change_detection_inhibitable; + gboolean device_is_media_change_detection_inhibited; gboolean device_is_read_only; gboolean device_is_drive; gboolean device_is_optical_disc; @@ -178,6 +181,9 @@ struct DevkitDisksDevicePrivate GPtrArray *holders_objpath; } info; + /* A list of current polling inhibitors (DevkitDisksInhibitor objects) */ + GList *polling_inhibitors; + /* We want S.M.A.R.T. to persist over change events */ gboolean drive_smart_is_capable; gboolean drive_smart_is_enabled; diff --git a/src/devkit-disks-device.c b/src/devkit-disks-device.c index 6e2c5f8..6539481 100644 --- a/src/devkit-disks-device.c +++ b/src/devkit-disks-device.c @@ -54,6 +54,8 @@ #include "devkit-disks-device-private.h" #include "devkit-disks-marshal.h" #include "mounts-file.h" +#include "devkit-disks-inhibitor.h" +#include "poller.h" /*--------------------------------------------------------------------------------------------------------------*/ #include "devkit-disks-device-glue.h" @@ -62,6 +64,9 @@ static void devkit_disks_device_class_init (DevkitDisksDeviceClass *klass); static void devkit_disks_device_init (DevkitDisksDevice *seat); static void devkit_disks_device_finalize (GObject *object); +static void polling_inhibitor_disconnected_cb (DevkitDisksInhibitor *inhibitor, + DevkitDisksDevice *device); + static void init_info (DevkitDisksDevice *device); static void free_info (DevkitDisksDevice *device); static gboolean update_info (DevkitDisksDevice *device); @@ -127,6 +132,9 @@ enum PROP_DEVICE_IS_PARTITION_TABLE, PROP_DEVICE_IS_REMOVABLE, PROP_DEVICE_IS_MEDIA_AVAILABLE, + PROP_DEVICE_IS_MEDIA_CHANGE_DETECTED, + PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_INHIBITABLE, + PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_INHIBITED, PROP_DEVICE_IS_READ_ONLY, PROP_DEVICE_IS_DRIVE, PROP_DEVICE_IS_OPTICAL_DISC, @@ -296,6 +304,15 @@ get_property (GObject *object, case PROP_DEVICE_IS_MEDIA_AVAILABLE: g_value_set_boolean (value, device->priv->info.device_is_media_available); break; + case PROP_DEVICE_IS_MEDIA_CHANGE_DETECTED: + g_value_set_boolean (value, device->priv->info.device_is_media_change_detected); + break; + case PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_INHIBITABLE: + g_value_set_boolean (value, device->priv->info.device_is_media_change_detection_inhibitable); + break; + case PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_INHIBITED: + g_value_set_boolean (value, device->priv->info.device_is_media_change_detection_inhibited); + break; case PROP_DEVICE_IS_READ_ONLY: g_value_set_boolean (value, device->priv->info.device_is_read_only); break; @@ -673,6 +690,18 @@ devkit_disks_device_class_init (DevkitDisksDeviceClass *klass) g_param_spec_boolean ("device-is-media-available", NULL, NULL, FALSE, G_PARAM_READABLE)); g_object_class_install_property ( object_class, + PROP_DEVICE_IS_MEDIA_CHANGE_DETECTED, + g_param_spec_boolean ("device-is-media-change-detected", NULL, NULL, FALSE, G_PARAM_READABLE)); + g_object_class_install_property ( + object_class, + PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_INHIBITABLE, + g_param_spec_boolean ("device-is-media-change-detection-inhibitable", NULL, NULL, FALSE, G_PARAM_READABLE)); + g_object_class_install_property ( + object_class, + PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_INHIBITED, + g_param_spec_boolean ("device-is-media-change-detection-inhibited", NULL, NULL, FALSE, G_PARAM_READABLE)); + g_object_class_install_property ( + object_class, PROP_DEVICE_IS_READ_ONLY, g_param_spec_boolean ("device-is-read-only", NULL, NULL, FALSE, G_PARAM_READABLE)); g_object_class_install_property ( @@ -1066,6 +1095,7 @@ static void devkit_disks_device_finalize (GObject *object) { DevkitDisksDevice *device; + GList *l; g_return_if_fail (object != NULL); g_return_if_fail (DEVKIT_IS_DISKS_DEVICE (object)); @@ -1085,6 +1115,13 @@ devkit_disks_device_finalize (GObject *object) g_ptr_array_foreach (device->priv->drive_smart_attributes, (GFunc) g_value_array_free, NULL); g_ptr_array_free (device->priv->drive_smart_attributes, TRUE); + for (l = device->priv->polling_inhibitors; l != NULL; l = l->next) { + DevkitDisksInhibitor *inhibitor = DEVKIT_DISKS_INHIBITOR (l->data); + g_signal_handlers_disconnect_by_func (inhibitor, polling_inhibitor_disconnected_cb, device); + g_object_unref (inhibitor); + } + g_list_free (device->priv->polling_inhibitors); + if (device->priv->linux_md_poll_timeout_id > 0) g_source_remove (device->priv->linux_md_poll_timeout_id); @@ -2672,6 +2709,9 @@ update_info (DevkitDisksDevice *device) } } + /* figure out if we need to poll the device */ + devkit_disks_device_local_update_media_detection (device); + ret = TRUE; out: @@ -2701,6 +2741,41 @@ out: return ret; } +/* returns TRUE if something changed */ +gboolean +devkit_disks_device_local_update_media_detection (DevkitDisksDevice *device) +{ + gboolean ret; + gboolean old_media_change_detected; + gboolean old_media_change_detection_inhibitable; + gboolean old_media_change_detection_inhibited; + + old_media_change_detected = device->priv->info.device_is_media_change_detected; + old_media_change_detection_inhibitable = device->priv->info.device_is_media_change_detected; + old_media_change_detection_inhibited = device->priv->info.device_is_media_change_detected; + + if (device->priv->info.device_is_removable) { + /* TODO: figure out if the device supports SATA AN */ + device->priv->info.device_is_media_change_detection_inhibitable = TRUE; + + if (device->priv->polling_inhibitors != NULL || + devkit_disks_daemon_local_has_polling_inhibitors (device->priv->daemon)) { + device->priv->info.device_is_media_change_detected = FALSE; + device->priv->info.device_is_media_change_detection_inhibited = TRUE; + } else { + device->priv->info.device_is_media_change_detected = TRUE; + device->priv->info.device_is_media_change_detection_inhibited = FALSE; + } + } + + ret = (old_media_change_detected != device->priv->info.device_is_media_change_detected) || + (old_media_change_detection_inhibitable != device->priv->info.device_is_media_change_detected) || + (old_media_change_detection_inhibited != device->priv->info.device_is_media_change_detected); + + return ret; +} + + gboolean devkit_disks_device_local_is_busy (DevkitDisksDevice *device) { @@ -8354,3 +8429,147 @@ pending: /*--------------------------------------------------------------------------------------------------------------*/ + +static void +polling_inhibitor_disconnected_cb (DevkitDisksInhibitor *inhibitor, + DevkitDisksDevice *device) +{ + device->priv->polling_inhibitors = g_list_remove (device->priv->polling_inhibitors, inhibitor); + g_signal_handlers_disconnect_by_func (inhibitor, polling_inhibitor_disconnected_cb, device); + g_object_unref (inhibitor); + + update_info (device); + devkit_disks_daemon_local_update_poller (device->priv->daemon); +} + +gboolean +devkit_disks_device_drive_inhibit_polling (DevkitDisksDevice *device, + char **options, + DBusGMethodInvocation *context) +{ + DevkitDisksInhibitor *inhibitor; + PolKitCaller *pk_caller; + guint n; + + if ((pk_caller = devkit_disks_damon_local_get_caller_for_context (device->priv->daemon, context)) == NULL) + goto out; + + if (!device->priv->info.device_is_drive) { + throw_error (context, DEVKIT_DISKS_ERROR_NOT_DRIVE, + "Device is not a drive"); + goto out; + } + + if (!device->priv->info.device_is_media_change_detection_inhibitable) { + throw_error (context, DEVKIT_DISKS_ERROR_FAILED, + "Media detection cannot be inhibited"); + goto out; + } + + if (!devkit_disks_damon_local_check_auth (device->priv->daemon, + pk_caller, + "org.freedesktop.devicekit.disks.inhibit-polling", + context)) + goto out; + + for (n = 0; options[n] != NULL; n++) { + const char *option = options[n]; + throw_error (context, + DEVKIT_DISKS_ERROR_INVALID_OPTION, + "Unknown option %s", option); + goto out; + } + + inhibitor = devkit_disks_inhibitor_new (context); + + device->priv->polling_inhibitors = g_list_prepend (device->priv->polling_inhibitors, inhibitor); + g_signal_connect (inhibitor, "disconnected", G_CALLBACK (polling_inhibitor_disconnected_cb), device); + + update_info (device); + devkit_disks_daemon_local_update_poller (device->priv->daemon); + + dbus_g_method_return (context, devkit_disks_inhibitor_get_cookie (inhibitor)); + +out: + if (pk_caller != NULL) + polkit_caller_unref (pk_caller); + return TRUE; +} + + +/*--------------------------------------------------------------------------------------------------------------*/ + +gboolean +devkit_disks_device_drive_uninhibit_polling (DevkitDisksDevice *device, + char *cookie, + DBusGMethodInvocation *context) +{ + const gchar *sender; + DevkitDisksInhibitor *inhibitor; + GList *l; + + sender = dbus_g_method_get_sender (context); + + inhibitor = NULL; + for (l = device->priv->polling_inhibitors; l != NULL; l = l->next) { + DevkitDisksInhibitor *i = DEVKIT_DISKS_INHIBITOR (l->data); + + if (g_strcmp0 (devkit_disks_inhibitor_get_unique_dbus_name (i), sender) == 0 && + g_strcmp0 (devkit_disks_inhibitor_get_cookie (i), cookie) == 0) { + inhibitor = i; + break; + } + } + + if (inhibitor == NULL) { + throw_error (context, + DEVKIT_DISKS_ERROR_FAILED, + "No such inhibitor"); + goto out; + } + + device->priv->polling_inhibitors = g_list_remove (device->priv->polling_inhibitors, inhibitor); + g_object_unref (inhibitor); + + update_info (device); + devkit_disks_daemon_local_update_poller (device->priv->daemon); + + dbus_g_method_return (context); + + out: + return TRUE; +} + +/*--------------------------------------------------------------------------------------------------------------*/ + +gboolean +devkit_disks_device_drive_poll_media (DevkitDisksDevice *device, + DBusGMethodInvocation *context) +{ + PolKitCaller *pk_caller; + + if ((pk_caller = devkit_disks_damon_local_get_caller_for_context (device->priv->daemon, context)) == NULL) + goto out; + + if (!device->priv->info.device_is_drive) { + throw_error (context, DEVKIT_DISKS_ERROR_NOT_DRIVE, + "Device is not a drive"); + goto out; + } + + if (!devkit_disks_damon_local_check_auth (device->priv->daemon, + pk_caller, + "org.freedesktop.devicekit.disks.inhibit-polling", + context)) + goto out; + + poller_poll_device (device->priv->info.device_file); + + dbus_g_method_return (context); + +out: + if (pk_caller != NULL) + polkit_caller_unref (pk_caller); + return TRUE; +} + diff --git a/src/devkit-disks-device.h b/src/devkit-disks-device.h index 9739260..5ffbc3f 100644 --- a/src/devkit-disks-device.h +++ b/src/devkit-disks-device.h @@ -79,6 +79,8 @@ void devkit_disks_device_local_set_unmounted (DevkitDisksDev gboolean devkit_disks_device_local_is_busy (DevkitDisksDevice *device); gboolean devkit_disks_device_local_partitions_are_busy (DevkitDisksDevice *device); +gboolean devkit_disks_device_local_update_media_detection (DevkitDisksDevice *device); + /* exported methods */ gboolean devkit_disks_device_job_cancel (DevkitDisksDevice *device, @@ -185,6 +187,17 @@ gboolean devkit_disks_device_linux_md_remove_component (DevkitDisksDevice *d char **options, DBusGMethodInvocation *context); +gboolean devkit_disks_device_drive_inhibit_polling (DevkitDisksDevice *device, + char **options, + DBusGMethodInvocation *context); + +gboolean devkit_disks_device_drive_uninhibit_polling (DevkitDisksDevice *device, + char *cookie, + DBusGMethodInvocation *context); + +gboolean devkit_disks_device_drive_poll_media (DevkitDisksDevice *device, + DBusGMethodInvocation *context); + G_END_DECLS #endif /* __DEVKIT_DISKS_DEVICE_H__ */ diff --git a/src/devkit-disks-inhibitor.c b/src/devkit-disks-inhibitor.c new file mode 100644 index 0000000..fbf0aa1 --- /dev/null +++ b/src/devkit-disks-inhibitor.c @@ -0,0 +1,157 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "devkit-disks-inhibitor.h" + +struct DevkitDisksInhibitorPrivate +{ + gchar *unique_dbus_name; + gchar *cookie; +}; + +enum +{ + DISCONNECTED_SIGNAL, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE (DevkitDisksInhibitor, devkit_disks_inhibitor, G_TYPE_OBJECT) + +static GList *inhibitors = NULL; + +static void +devkit_disks_inhibitor_finalize (GObject *object) +{ + DevkitDisksInhibitor *inhibitor; + + inhibitor = DEVKIT_DISKS_INHIBITOR (object); + + inhibitors = g_list_remove (inhibitors, inhibitor); + + g_free (inhibitor->priv->unique_dbus_name); + g_free (inhibitor->priv->cookie); + + G_OBJECT_CLASS (devkit_disks_inhibitor_parent_class)->finalize (object); +} + +static void +devkit_disks_inhibitor_init (DevkitDisksInhibitor *inhibitor) +{ + inhibitor->priv = G_TYPE_INSTANCE_GET_PRIVATE (inhibitor, DEVKIT_TYPE_DISKS_INHIBITOR, DevkitDisksInhibitorPrivate); +} + +static void +devkit_disks_inhibitor_class_init (DevkitDisksInhibitorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = devkit_disks_inhibitor_finalize; + + g_type_class_add_private (klass, sizeof (DevkitDisksInhibitorPrivate)); + + signals[DISCONNECTED_SIGNAL] = + g_signal_new ("disconnected", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +DevkitDisksInhibitor * +devkit_disks_inhibitor_new (DBusGMethodInvocation *context) +{ + DevkitDisksInhibitor *inhibitor; + static gint inhibitor_count = 0; + + inhibitor = DEVKIT_DISKS_INHIBITOR (g_object_new (DEVKIT_TYPE_DISKS_INHIBITOR, NULL)); + + inhibitor->priv->unique_dbus_name = g_strdup (dbus_g_method_get_sender (context)); + + /* TODO: maybe use a real random number (if it turns out we need this to be cryptographically secure etc.) */ + inhibitor->priv->cookie = g_strdup_printf ("devkit_disks_inhibitor_%d", inhibitor_count++); + + inhibitors = g_list_prepend (inhibitors, inhibitor); + + return inhibitor; +} + +const gchar * +devkit_disks_inhibitor_get_unique_dbus_name (DevkitDisksInhibitor *inhibitor) +{ + return inhibitor->priv->unique_dbus_name; +} + +const gchar * +devkit_disks_inhibitor_get_cookie (DevkitDisksInhibitor *inhibitor) +{ + return inhibitor->priv->cookie; +} + + +void devkit_disks_inhibitor_name_owner_changed (DBusMessage *message); + +void +devkit_disks_inhibitor_name_owner_changed (DBusMessage *message) +{ + + if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) { + char *name; + char *new_owner; + char *old_owner; + + if (!dbus_message_get_args (message, NULL, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &old_owner, + DBUS_TYPE_STRING, &new_owner, + DBUS_TYPE_INVALID)) { + + g_warning ("The NameOwnerChanged signal has the wrong signature."); + goto out; + } + + if (strlen (new_owner) == 0) { + GList *l; + + for (l = inhibitors; l != NULL; l = l->next) { + DevkitDisksInhibitor *inhibitor = DEVKIT_DISKS_INHIBITOR (l->data); + + g_debug (" looking at %s", inhibitor->priv->unique_dbus_name); + if (g_strcmp0 (name, inhibitor->priv->unique_dbus_name) == 0) { + g_signal_emit_by_name (inhibitor, "disconnected"); + } + } + } + } + + out: + ; +} + diff --git a/src/devkit-disks-inhibitor.h b/src/devkit-disks-inhibitor.h new file mode 100644 index 0000000..b6434dd --- /dev/null +++ b/src/devkit-disks-inhibitor.h @@ -0,0 +1,58 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __DEVKIT_DISKS_INHIBITOR_H__ +#define __DEVKIT_DISKS_INHIBITOR_H__ + +#include +#include + +G_BEGIN_DECLS + +#define DEVKIT_TYPE_DISKS_INHIBITOR (devkit_disks_inhibitor_get_type ()) +#define DEVKIT_DISKS_INHIBITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), DEVKIT_TYPE_DISKS_INHIBITOR, DevkitDisksInhibitor)) +#define DEVKIT_DISKS_INHIBITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), DEVKIT_TYPE_DISKS_INHIBITOR, DevkitDisksInhibitorClass)) +#define DEVKIT_IS_DISKS_INHIBITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), DEVKIT_TYPE_DISKS_INHIBITOR)) +#define DEVKIT_IS_DISKS_INHIBITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), DEVKIT_TYPE_DISKS_INHIBITOR)) +#define DEVKIT_DISKS_INHIBITOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), DEVKIT_TYPE_DISKS_INHIBITOR, DevkitDisksInhibitorClass)) + +typedef struct DevkitDisksInhibitor DevkitDisksInhibitor; +typedef struct DevkitDisksInhibitorClass DevkitDisksInhibitorClass; +typedef struct DevkitDisksInhibitorPrivate DevkitDisksInhibitorPrivate; + +struct DevkitDisksInhibitor +{ + GObject parent; + DevkitDisksInhibitorPrivate *priv; +}; + +struct DevkitDisksInhibitorClass +{ + GObjectClass parent_class; +}; + +GType devkit_disks_inhibitor_get_type (void) G_GNUC_CONST; +DevkitDisksInhibitor *devkit_disks_inhibitor_new (DBusGMethodInvocation *context); +const gchar *devkit_disks_inhibitor_get_unique_dbus_name (DevkitDisksInhibitor *inhibitor); +const gchar *devkit_disks_inhibitor_get_cookie (DevkitDisksInhibitor *inhibitor); + +G_END_DECLS + +#endif /* __DEVKIT_DISKS_INHIBITOR_H__ */ diff --git a/src/main.c b/src/main.c index 05fc47c..6989920 100644 --- a/src/main.c +++ b/src/main.c @@ -43,6 +43,7 @@ #include #include +#include "poller.h" #include "devkit-disks-daemon.h" @@ -130,6 +131,7 @@ main (int argc, char **argv) }; ret = 1; + error = NULL; /* run with a controlled path */ if (!g_setenv ("PATH", PACKAGE_LIBEXEC_DIR ":/sbin:/bin:/usr/sbin:/usr/bin", TRUE)) { @@ -145,12 +147,16 @@ main (int argc, char **argv) g_type_init (); + /* fork the polling process early */ + if (!poller_setup (argc, argv)) { + goto out; + } + context = g_option_context_new ("DeviceKit Disks Daemon"); g_option_context_add_main_entries (context, entries, NULL); g_option_context_parse (context, &argc, &argv, NULL); g_option_context_free (context); - error = NULL; bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); if (bus == NULL) { g_warning ("Couldn't connect to system bus: %s", error->message); diff --git a/src/org.freedesktop.DeviceKit.Disks.Device.xml b/src/org.freedesktop.DeviceKit.Disks.Device.xml index f6bcd47..e896b1c 100644 --- a/src/org.freedesktop.DeviceKit.Disks.Device.xml +++ b/src/org.freedesktop.DeviceKit.Disks.Device.xml @@ -1021,6 +1021,98 @@ + + + + Inhibit options. Currently no options are recognized. + + + + + A cookie that can be used in the + DriveUninhibitPolling() method + to stop inhibiting polling of the device. + + + + + + + Inhibits the daemon from polling the device for media changes. + + + + The caller will need one of the following PolicyKit authorizations: + + + org.freedesktop.devicekit.disks.inhibit-polling + To inhibit polling + + + + + if the caller lacks the appropriate PolicyKit authorization + if incoming parameters are invalid or an unknown error occured + device is not a drive + + + + + + + + + + + + A cookie obtained from the + DriveInhibitPolling() method. + + + + + + + Uninhibits daemon from polling the device for media changes. + + + + if the given cookie is malformed + + + + + + + + + + + + + + Polls the drive for media. This is typically only useful when the + device-is-media-change-detected property + is FALSE. + + + + The caller will need one of the following PolicyKit authorizations: + + + org.freedesktop.devicekit.disks.inhibit-polling + To inhibit polling + + + + + if an unknown error occured + + + + + + @@ -1354,6 +1446,21 @@ TRUE if media is available in the device. + + + TRUE if media changes are detected. + + + + + TRUE if it is possible to inhibit media detection on the device (to avoid keeping the device in a high power state). + + + + + TRUE if media detection is inhibited (to avoid keeping the device in a high power state). + + TRUE if the device read-only. diff --git a/src/org.freedesktop.DeviceKit.Disks.xml b/src/org.freedesktop.DeviceKit.Disks.xml index 4189c0a..c18c101 100644 --- a/src/org.freedesktop.DeviceKit.Disks.xml +++ b/src/org.freedesktop.DeviceKit.Disks.xml @@ -65,6 +65,68 @@ + + + + Inhibit options. Currently no options are recognized. + + + + + A cookie that can be used in the + DriveUninhibitAllPolling() method + to stop inhibiting polling of all devices. + + + + + + + Inhibits the daemon from polling devices for media changes. + + + + The caller will need one of the following PolicyKit authorizations: + + + org.freedesktop.devicekit.disks.inhibit-polling + To inhibit polling + + + + + if the caller lacks the appropriate PolicyKit authorization + if incoming parameters are invalid or an unknown error occured + + + + + + + + + + + + A cookie obtained from the + DriveInhibitAllPolling() method. + + + + + + + Uninhibits daemon from polling devices for media changes. + + + + if the given cookie is malformed + + + + + + diff --git a/src/poller.c b/src/poller.c new file mode 100644 index 0000000..7dcc44c --- /dev/null +++ b/src/poller.c @@ -0,0 +1,235 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 David Zeuthen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "poller.h" +#include "devkit-disks-device.h" +#include "devkit-disks-device-private.h" + +static gchar **poller_devices_to_poll = NULL; + +static guint poller_timeout_id = 0; + +void +poller_poll_device (const gchar *device_file) +{ + gboolean is_cdrom; + int fd; + + /* the device file is the canonical device file from udev */ + is_cdrom = (g_str_has_prefix (device_file, "/dev/sr") || g_str_has_prefix (device_file, "/dev/scd")); + + g_debug ("polling '%s'", device_file); + + if (is_cdrom) { + /* optical drives need special care + * + * - use O_NONBLOCK to avoid closing the door + * - use O_EXCL to avoid interferring with cd burning software / audio playback / etc + */ + fd = open (device_file, O_RDONLY | O_NONBLOCK | O_EXCL); + if (fd != -1) { + close (fd); + } + + } else { + fd = open (device_file, O_RDONLY); + if (fd != -1) { + close (fd); + } + } +} + + +static gboolean +poller_timeout_cb (gpointer user_data) +{ + guint n; + + for (n = 0; poller_devices_to_poll != NULL && poller_devices_to_poll[n] != NULL; n++) { + const gchar *device_file = poller_devices_to_poll[n]; + + poller_poll_device (device_file); + } + + /* don't remove the source */ + return TRUE; +} + +static gboolean +poller_have_data (GIOChannel *channel, + GIOCondition condition, + gpointer user_data) +{ + gchar *line; + gsize line_length; + GError *error; + gint status; + + error = NULL; + + again: + status = g_io_channel_read_line (channel, + &line, + &line_length, + NULL, + &error); + if (error != NULL) { + g_warning ("Error reading line from daemon: %s", error->message); + g_error_free (error); + goto out; + } + if (status == G_IO_STATUS_AGAIN) { + goto again; + } + + //g_debug ("polling process read '%s'", line); + + if (line[line_length - 1] == '\n') + line[line_length - 1] = '\0'; + + if (line[line_length - 2] == ' ') + line[line_length - 2] = '\0'; + + g_strfreev (poller_devices_to_poll); + poller_devices_to_poll = g_strsplit (line, " ", 0); + + if (g_strv_length (poller_devices_to_poll) == 0) { + if (poller_timeout_id > 0) { + g_source_remove (poller_timeout_id); + poller_timeout_id = 0; + } + + g_print ("poller: not polling any devices\n"); + } else { + g_print ("poller: polling %s", line); + + if (poller_timeout_id == 0) { + poller_timeout_id = g_timeout_add_seconds (2, poller_timeout_cb, NULL); + } + } + + g_free (line); + + out: + /* keep the IOChannel around */ + return TRUE; +} + +static void +poller_run (gint fd) +{ + GMainLoop *loop; + GIOChannel *io_channel; + + loop = g_main_loop_new (NULL, FALSE); + + io_channel = g_io_channel_unix_new (fd); + g_io_channel_set_flags (io_channel, G_IO_FLAG_NONBLOCK, NULL); + g_io_add_watch (io_channel, G_IO_IN, poller_have_data, NULL); + + g_main_loop_run (loop); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static gint poller_daemon_write_end_fd; + +gboolean +poller_setup (int argc, char *argv[]) +{ + gint pipefds[2]; + gboolean ret; + + ret = FALSE; + + if (pipe (pipefds) != 0) { + g_warning ("Couldn't set up polling process, pipe() failed: %m"); + goto out; + } + + switch (fork ()) { + case 0: + /* child */ + close (pipefds[1]); /* close write end */ + poller_run (pipefds[0]); + break; + + default: + /* parent */ + close (pipefds[0]); /* close read end */ + poller_daemon_write_end_fd = pipefds[1]; + break; + + case -1: + g_warning ("Couldn't set up polling process, fork() failed: %m"); + goto out; + break; + } + + ret = TRUE; + + out: + return ret; +} + +void +poller_set_devices (GList *devices) +{ + GList *l; + gchar **device_array; + guint n; + gchar *devices_to_poll; + static gchar *devices_currently_polled = NULL; + + device_array = g_new0 (gchar *, g_list_length (devices) + 2); + + for (l = devices, n = 0; l != NULL; l = l->next) { + DevkitDisksDevice *device = DEVKIT_DISKS_DEVICE (l->data); + + device_array[n++] = device->priv->info.device_file; + } + + g_qsort_with_data (device_array, n, sizeof (gchar *), (GCompareDataFunc) g_strcmp0, NULL); + + device_array[n] = "\n"; + + devices_to_poll = g_strjoinv (" ", device_array); + g_free (device_array); + + if (g_strcmp0 (devices_to_poll, devices_currently_polled) != 0) { + g_free (devices_currently_polled); + devices_currently_polled = devices_to_poll; + + write (poller_daemon_write_end_fd, devices_currently_polled, strlen (devices_currently_polled)); + //g_debug ("Wanna poll: '%s'", devices_currently_polled); + } else { + g_free (devices_to_poll); + } +} diff --git a/src/poller.h b/src/poller.h new file mode 100644 index 0000000..c1ce073 --- /dev/null +++ b/src/poller.h @@ -0,0 +1,31 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 David Zeuthen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __POLLER_H__ +#define __POLLER_H__ + +#include + +gboolean poller_setup (int argc, char *argv[]); +void poller_set_devices (GList *devices); +void poller_poll_device (const gchar *device_file); + + +#endif /* __POLLER_H */ diff --git a/tools/devkit-disks-bash-completion.sh b/tools/devkit-disks-bash-completion.sh index ebb0cce..e5aa556 100644 --- a/tools/devkit-disks-bash-completion.sh +++ b/tools/devkit-disks-bash-completion.sh @@ -10,6 +10,8 @@ __devkit_disks() { if [ "${COMP_WORDS[$(($COMP_CWORD - 1))]}" = "--show-info" ] ; then COMPREPLY=($(compgen -W "$(devkit-disks --enumerate)" -- $cur)) + elif [ "${COMP_WORDS[$(($COMP_CWORD - 1))]}" = "--inhibit-polling" ] ; then + COMPREPLY=($(compgen -W "$(devkit-disks --enumerate)" -- $cur)) elif [ "${COMP_WORDS[$(($COMP_CWORD - 1))]}" = "--mount" ] ; then COMPREPLY=($(compgen -W "$(devkit-disks --enumerate)" -- $cur)) elif [ "${COMP_WORDS[$(($COMP_CWORD - 1))]}" = "--unmount" ] ; then @@ -17,7 +19,7 @@ __devkit_disks() { elif [ "${COMP_WORDS[$(($COMP_CWORD - 1))]}" = "--create-fs" ] ; then COMPREPLY=($(compgen -W "$(devkit-disks --enumerate)" -- $cur)) else - COMPREPLY=($(IFS=: compgen -S' ' -W "--inhibit:--enumerate:--monitor:--monitor-detail:--show-info:--help:--mount:--mount-fstype:--mount-options:--unmount:--unmount-options:--create-fs:--create-fs-type:--create-fs-options" -- $cur)) + COMPREPLY=($(IFS=: compgen -S' ' -W "--inhibit-polling:--inhibit-all-polling:--enumerate:--monitor:--monitor-detail:--show-info:--help:--mount:--mount-fstype:--mount-options:--unmount:--unmount-options:--create-fs:--create-fs-type:--create-fs-options" -- $cur)) fi } diff --git a/tools/devkit-disks.c b/tools/devkit-disks.c index ea3e2e3..356416a 100644 --- a/tools/devkit-disks.c +++ b/tools/devkit-disks.c @@ -55,6 +55,8 @@ static gboolean opt_enumerate = FALSE; static gboolean opt_monitor = FALSE; static gboolean opt_monitor_detail = FALSE; static char *opt_show_info = NULL; +static char *opt_inhibit_polling = NULL; +static gboolean opt_inhibit_all_polling = FALSE; static char *opt_mount = NULL; static char *opt_mount_fstype = NULL; static char *opt_mount_options = NULL; @@ -311,7 +313,7 @@ print_job (gboolean job_in_progress, { if (job_in_progress) { if (job_num_tasks > 0) { - g_print (" job underway: %s: %d/%d tasks (%s", + g_print (" job underway: %s: %d/%d tasks (%s", job_id, job_cur_task + 1, job_num_tasks, @@ -323,14 +325,14 @@ print_job (gboolean job_in_progress, g_print (", initiated by uid %d", job_initiated_by_uid); g_print (")\n"); } else { - g_print (" job underway: %s: unknown progress", job_id); + g_print (" job underway: %s: unknown progress", job_id); if (job_is_cancellable) g_print (", cancellable"); g_print (", initiated by uid %d", job_initiated_by_uid); g_print ("\n"); } } else { - g_print (" job underway: no\n"); + g_print (" job underway: no\n"); } } @@ -405,6 +407,9 @@ typedef struct gboolean device_is_partition_table; gboolean device_is_removable; gboolean device_is_media_available; + gboolean device_is_media_change_detected; + gboolean device_is_media_change_detection_inhibitable; + gboolean device_is_media_change_detection_inhibited; gboolean device_is_read_only; gboolean device_is_drive; gboolean device_is_optical_disc; @@ -531,6 +536,12 @@ collect_props (const char *key, const GValue *value, DeviceProperties *props) props->device_is_removable = g_value_get_boolean (value); else if (strcmp (key, "device-is-media-available") == 0) props->device_is_media_available = g_value_get_boolean (value); + else if (strcmp (key, "device-is-media-change-detected") == 0) + props->device_is_media_change_detected = g_value_get_boolean (value); + else if (strcmp (key, "device-is-media-change-detection-inhibitable") == 0) + props->device_is_media_change_detection_inhibitable = g_value_get_boolean (value); + else if (strcmp (key, "device-is-media-change-detection-inhibited") == 0) + props->device_is_media_change_detection_inhibited = g_value_get_boolean (value); else if (strcmp (key, "device-is-read-only") == 0) props->device_is_read_only = g_value_get_boolean (value); else if (strcmp (key, "device-is-drive") == 0) @@ -877,22 +888,25 @@ do_show_info (const char *object_path) return; g_print ("Showing information for %s\n", object_path); - g_print (" native-path: %s\n", props->native_path); - g_print (" device-file: %s\n", props->device_file); + g_print (" native-path: %s\n", props->native_path); + g_print (" device-file: %s\n", props->device_file); for (n = 0; props->device_file_by_id[n] != NULL; n++) - g_print (" by-id: %s\n", (char *) props->device_file_by_id[n]); + g_print (" by-id: %s\n", (char *) props->device_file_by_id[n]); for (n = 0; props->device_file_by_path[n] != NULL; n++) - g_print (" by-path: %s\n", (char *) props->device_file_by_path[n]); - g_print (" system internal: %d\n", props->device_is_system_internal); - g_print (" removable: %d\n", props->device_is_removable); - g_print (" has media: %d\n", props->device_is_media_available); - g_print (" is read only: %d\n", props->device_is_read_only); - g_print (" is mounted: %d\n", props->device_is_mounted); - g_print (" is busy: %d\n", props->device_is_busy); - g_print (" mount path: %s\n", props->device_mount_path); - g_print (" mounted by uid: %d\n", props->device_mounted_by_uid); - g_print (" size: %" G_GUINT64_FORMAT "\n", props->device_size); - g_print (" block size: %" G_GUINT64_FORMAT "\n", props->device_block_size); + g_print (" by-path: %s\n", (char *) props->device_file_by_path[n]); + g_print (" system internal: %d\n", props->device_is_system_internal); + g_print (" removable: %d\n", props->device_is_removable); + g_print (" has media: %d\n", props->device_is_media_available); + g_print (" detects change: %d\n", props->device_is_media_change_detected); + g_print (" detection inhibitable: %d\n", props->device_is_media_change_detection_inhibitable); + g_print (" detection inhibited: %d\n", props->device_is_media_change_detection_inhibited); + g_print (" is read only: %d\n", props->device_is_read_only); + g_print (" is mounted: %d\n", props->device_is_mounted); + g_print (" is busy: %d\n", props->device_is_busy); + g_print (" mount path: %s\n", props->device_mount_path); + g_print (" mounted by uid: %d\n", props->device_mounted_by_uid); + g_print (" size: %" G_GUINT64_FORMAT "\n", props->device_size); + g_print (" block size: %" G_GUINT64_FORMAT "\n", props->device_block_size); print_job (props->job_in_progress, props->job_id, @@ -902,11 +916,11 @@ do_show_info (const char *object_path) props->job_cur_task, props->job_cur_task_id, props->job_cur_task_percentage); - g_print (" usage: %s\n", props->id_usage); - g_print (" type: %s\n", props->id_type); - g_print (" version: %s\n", props->id_version); - g_print (" uuid: %s\n", props->id_uuid); - g_print (" label: %s\n", props->id_label); + g_print (" usage: %s\n", props->id_usage); + g_print (" type: %s\n", props->id_type); + g_print (" version: %s\n", props->id_version); + g_print (" uuid: %s\n", props->id_uuid); + g_print (" label: %s\n", props->id_label); if (props->device_is_linux_md_component) { struct tm *time_tm; time_t time; @@ -917,101 +931,101 @@ do_show_info (const char *object_path) strftime (time_buf, sizeof time_buf, "%c", time_tm); g_print (" linux md component:\n"); - g_print (" RAID level: %s\n", props->linux_md_component_level); - g_print (" num comp: %d\n", props->linux_md_component_num_raid_devices); - g_print (" uuid: %s\n", props->linux_md_component_uuid); - g_print (" home host: %s\n", props->linux_md_component_home_host); - g_print (" name: %s\n", props->linux_md_component_name); - g_print (" version: %s\n", props->linux_md_component_version); - g_print (" update time: %" G_GUINT64_FORMAT " (%s)\n", props->linux_md_component_update_time, time_buf); - g_print (" events: %" G_GUINT64_FORMAT "\n", props->linux_md_component_events); + g_print (" RAID level: %s\n", props->linux_md_component_level); + g_print (" num comp: %d\n", props->linux_md_component_num_raid_devices); + g_print (" uuid: %s\n", props->linux_md_component_uuid); + g_print (" home host: %s\n", props->linux_md_component_home_host); + g_print (" name: %s\n", props->linux_md_component_name); + g_print (" version: %s\n", props->linux_md_component_version); + g_print (" update time: %" G_GUINT64_FORMAT " (%s)\n", props->linux_md_component_update_time, time_buf); + g_print (" events: %" G_GUINT64_FORMAT "\n", props->linux_md_component_events); } if (props->device_is_linux_md) { g_print (" linux md:\n"); - g_print (" RAID level: %s\n", props->linux_md_level); - g_print (" uuid: %s\n", props->linux_md_uuid); - g_print (" home host: %s\n", props->linux_md_home_host); - g_print (" name: %s\n", props->linux_md_name); - g_print (" num comp: %d\n", props->linux_md_num_raid_devices); - g_print (" version: %s\n", props->linux_md_version); - g_print (" degraded: %d\n", props->linux_md_is_degraded); - g_print (" sync action: %s\n", props->linux_md_sync_action); + g_print (" RAID level: %s\n", props->linux_md_level); + g_print (" uuid: %s\n", props->linux_md_uuid); + g_print (" home host: %s\n", props->linux_md_home_host); + g_print (" name: %s\n", props->linux_md_name); + g_print (" num comp: %d\n", props->linux_md_num_raid_devices); + g_print (" version: %s\n", props->linux_md_version); + g_print (" degraded: %d\n", props->linux_md_is_degraded); + g_print (" sync action: %s\n", props->linux_md_sync_action); if (strcmp (props->linux_md_sync_action, "idle") != 0) { - g_print (" complete: %3.01f%%\n", props->linux_md_sync_percentage); - g_print (" speed: %" G_GINT64_FORMAT " bytes/sec\n", props->linux_md_sync_speed); + g_print (" complete: %3.01f%%\n", props->linux_md_sync_percentage); + g_print (" speed: %" G_GINT64_FORMAT " bytes/sec\n", props->linux_md_sync_speed); } g_print (" slaves:\n"); for (n = 0; props->linux_md_slaves[n] != NULL; n++) - g_print (" %s (state: %s)\n", + g_print (" %s (state: %s)\n", props->linux_md_slaves[n], props->linux_md_slaves_state[n]); } if (props->device_is_luks) { g_print (" luks device:\n"); - g_print (" holder: %s\n", props->luks_holder); + g_print (" holder: %s\n", props->luks_holder); } if (props->device_is_luks_cleartext) { g_print (" cleartext luks device:\n"); - g_print (" backed by: %s\n", props->luks_cleartext_slave); - g_print (" unlocked by: uid %d\n", props->luks_cleartext_unlocked_by_uid); + g_print (" backed by: %s\n", props->luks_cleartext_slave); + g_print (" unlocked by: uid %d\n", props->luks_cleartext_unlocked_by_uid); } if (props->device_is_partition_table) { g_print (" partition table:\n"); - g_print (" scheme: %s\n", props->partition_table_scheme); - g_print (" count: %d\n", props->partition_table_count); - g_print (" max number: %d\n", props->partition_table_max_number); + g_print (" scheme: %s\n", props->partition_table_scheme); + g_print (" count: %d\n", props->partition_table_count); + g_print (" max number: %d\n", props->partition_table_max_number); } if (props->device_is_partition) { g_print (" partition:\n"); - g_print (" part of: %s\n", props->partition_slave); - g_print (" scheme: %s\n", props->partition_scheme); - g_print (" number: %d\n", props->partition_number); - g_print (" type: %s\n", props->partition_type); - g_print (" flags: "); + g_print (" part of: %s\n", props->partition_slave); + g_print (" scheme: %s\n", props->partition_scheme); + g_print (" number: %d\n", props->partition_number); + g_print (" type: %s\n", props->partition_type); + g_print (" flags: "); for (n = 0; props->partition_flags[n] != NULL; n++) g_print (" %s", (char *) props->partition_flags[n]); g_print ("\n"); - g_print (" offset: %" G_GINT64_FORMAT "\n", props->partition_offset); - g_print (" size: %" G_GINT64_FORMAT "\n", props->partition_size); - g_print (" label: %s\n", props->partition_label); - g_print (" uuid: %s\n", props->partition_uuid); + g_print (" offset: %" G_GINT64_FORMAT "\n", props->partition_offset); + g_print (" size: %" G_GINT64_FORMAT "\n", props->partition_size); + g_print (" label: %s\n", props->partition_label); + g_print (" uuid: %s\n", props->partition_uuid); } if (props->device_is_optical_disc) { g_print (" optical disc:\n"); - g_print (" recordable: %d\n", props->optical_disc_is_recordable); - g_print (" rewritable: %d\n", props->optical_disc_is_rewritable); - g_print (" blank: %d\n", props->optical_disc_is_blank); - g_print (" appendable: %d\n", props->optical_disc_is_appendable); - g_print (" closed: %d\n", props->optical_disc_is_closed); - g_print (" has audio: %d\n", props->optical_disc_has_audio); - g_print (" num tracks: %d\n", props->optical_disc_num_tracks); - g_print (" num sessions: %d\n", props->optical_disc_num_sessions); + g_print (" recordable: %d\n", props->optical_disc_is_recordable); + g_print (" rewritable: %d\n", props->optical_disc_is_rewritable); + g_print (" blank: %d\n", props->optical_disc_is_blank); + g_print (" appendable: %d\n", props->optical_disc_is_appendable); + g_print (" closed: %d\n", props->optical_disc_is_closed); + g_print (" has audio: %d\n", props->optical_disc_has_audio); + g_print (" num tracks: %d\n", props->optical_disc_num_tracks); + g_print (" num sessions: %d\n", props->optical_disc_num_sessions); } if (props->device_is_drive) { g_print (" drive:\n"); - g_print (" vendor: %s\n", props->drive_vendor); - g_print (" model: %s\n", props->drive_model); - g_print (" revision: %s\n", props->drive_revision); - g_print (" serial: %s\n", props->drive_serial); - g_print (" ejectable: %d\n", props->drive_is_media_ejectable); - g_print (" require eject: %d\n", props->drive_requires_eject); - g_print (" media: %s\n", props->drive_media); - g_print (" compat: "); + g_print (" vendor: %s\n", props->drive_vendor); + g_print (" model: %s\n", props->drive_model); + g_print (" revision: %s\n", props->drive_revision); + g_print (" serial: %s\n", props->drive_serial); + g_print (" ejectable: %d\n", props->drive_is_media_ejectable); + g_print (" require eject: %d\n", props->drive_requires_eject); + g_print (" media: %s\n", props->drive_media); + g_print (" compat: "); for (n = 0; props->drive_media_compatibility[n] != NULL; n++) g_print (" %s", (char *) props->drive_media_compatibility[n]); g_print ("\n"); if (props->drive_connection_interface == NULL || strlen (props->drive_connection_interface) == 0) g_print (" interface: (unknown)\n"); else - g_print (" interface: %s\n", props->drive_connection_interface); + g_print (" interface: %s\n", props->drive_connection_interface); if (props->drive_connection_speed == 0) - g_print (" if speed: (unknown)\n"); + g_print (" if speed: (unknown)\n"); else - g_print (" if speed: %" G_GINT64_FORMAT " bits/s\n", props->drive_connection_speed); + g_print (" if speed: %" G_GINT64_FORMAT " bits/s\n", props->drive_connection_speed); if (!props->drive_smart_is_capable) { - g_print (" S.M.A.R.T.: not capable\n"); + g_print (" S.M.A.R.T.: not capable\n"); } else if (props->drive_smart_time_collected == 0) { - g_print (" S.M.A.R.T.: not collected\n"); + g_print (" S.M.A.R.T.: not collected\n"); } else { struct tm *time_tm; time_t time; @@ -1021,19 +1035,19 @@ do_show_info (const char *object_path) time_tm = localtime (&time); strftime (time_buf, sizeof time_buf, "%c", time_tm); - g_print (" S.M.A.R.T.: Information collected at %s\n", time_buf); + g_print (" S.M.A.R.T.: Information collected at %s\n", time_buf); if (!props->drive_smart_is_capable) { - g_print (" not capable\n"); + g_print (" not capable\n"); } else if (!props->drive_smart_is_enabled) { - g_print (" not enabled\n"); + g_print (" not enabled\n"); } else { - g_print (" assessment: %s\n", + g_print (" assessment: %s\n", props->drive_smart_is_failing ? "FAILING" : "Passed"); - g_print (" temperature: %g° C / %g° F\n", + g_print (" temperature: %g° C / %g° F\n", props->drive_smart_temperature, 9 * props->drive_smart_temperature / 5 + 32); - g_print (" powered on: %" G_GUINT64_FORMAT " hours\n", props->drive_smart_time_powered_on / 3600); + g_print (" powered on: %" G_GUINT64_FORMAT " hours\n", props->drive_smart_time_powered_on / 3600); //g_print (" 196 Reallocated_Event_Count 0x0032 100 100 0 443023360\n", #if 0 int m; @@ -1054,6 +1068,81 @@ do_show_info (const char *object_path) device_properties_free (props); } +/* ---------------------------------------------------------------------------------------------------- */ + +static void +do_inhibit_polling (const char *object_path) +{ + char *cookie; + DBusGProxy *proxy; + GError *error; + char **options; + + options = NULL; + + proxy = dbus_g_proxy_new_for_name (bus, + "org.freedesktop.DeviceKit.Disks", + object_path, + "org.freedesktop.DeviceKit.Disks.Device"); + + error = NULL; + if (!org_freedesktop_DeviceKit_Disks_Device_drive_inhibit_polling (proxy, + (const char **) options, + &cookie, + &error)) { + g_print ("Inhibit polling failed: %s\n", error->message); + g_error_free (error); + goto out; + } + + g_print ("Inhibiting polling on %s. Press Ctrl+C to exit.\n", object_path); + while (TRUE) + sleep (100000000); + + g_free (cookie); +out: + ; +} + +/* ---------------------------------------------------------------------------------------------------- */ + + +static void +do_inhibit_all_polling (void) +{ + char *cookie; + DBusGProxy *proxy; + GError *error; + char **options; + + options = NULL; + + proxy = dbus_g_proxy_new_for_name (bus, + "org.freedesktop.DeviceKit.Disks", + "/", + "org.freedesktop.DeviceKit.Disks"); + + error = NULL; + if (!org_freedesktop_DeviceKit_Disks_drive_inhibit_all_polling (proxy, + (const char **) options, + &cookie, + &error)) { + g_print ("Inhibit all polling failed: %s\n", error->message); + g_error_free (error); + goto out; + } + + g_print ("Inhibiting polling on all devices. Press Ctrl+C to exit.\n"); + while (TRUE) + sleep (100000000); + + g_free (cookie); +out: + ; +} + +/* ---------------------------------------------------------------------------------------------------- */ + int main (int argc, char **argv) { @@ -1066,6 +1155,8 @@ main (int argc, char **argv) { "monitor", 0, 0, G_OPTION_ARG_NONE, &opt_monitor, "Monitor activity from the disk daemon", NULL }, { "monitor-detail", 0, 0, G_OPTION_ARG_NONE, &opt_monitor_detail, "Monitor with detail", NULL }, { "show-info", 0, 0, G_OPTION_ARG_STRING, &opt_show_info, "Show information about object path", NULL }, + { "inhibit-polling", 0, 0, G_OPTION_ARG_STRING, &opt_inhibit_polling, "Inhibit polling", NULL }, + { "inhibit-all-polling", 0, 0, G_OPTION_ARG_NONE, &opt_inhibit_all_polling, "Inhibit all polling", NULL }, { "mount", 0, 0, G_OPTION_ARG_STRING, &opt_mount, "Mount the device given by the object path", NULL }, { "mount-fstype", 0, 0, G_OPTION_ARG_STRING, &opt_mount_fstype, "Specify file system type", NULL }, @@ -1150,6 +1241,10 @@ main (int argc, char **argv) goto out; } else if (opt_show_info != NULL) { do_show_info (opt_show_info); + } else if (opt_inhibit_polling != NULL) { + do_inhibit_polling (opt_inhibit_polling); + } else if (opt_inhibit_all_polling) { + do_inhibit_all_polling (); } else if (opt_mount != NULL) { do_mount (opt_mount, opt_mount_fstype, opt_mount_options); } else if (opt_unmount != NULL) { -- 2.7.4