/*--------------------------------------------------------------------------------------------------------------*/
-static void
-update_mount_state (DevkitDisksDaemon *daemon, GList *devices)
+void
+devkit_disks_daemon_local_update_mount_state (DevkitDisksDaemon *daemon, GList *devices, gboolean emit_changed)
{
GList *l;
GList *mounts;
/* same mount path; no changes */
} else {
/* device was just mounted... or the mount path changed */
- devkit_disks_device_local_set_mounted (device, mount_path);
+ devkit_disks_device_local_set_mounted (device, mount_path, emit_changed);
}
/* we're mounted so remove from list of devices (see below) */
device_mount_path = devkit_disks_device_local_get_mount_path (device);
if (device_mount_path != NULL) {
- devkit_disks_device_local_set_unmounted (device);
+ devkit_disks_device_local_set_unmounted (device, emit_changed);
}
}
device_add (DevkitDisksDaemon *daemon, const char *native_path, gboolean emit_event)
{
DevkitDisksDevice *device;
- GList *l;
device = g_hash_table_lookup (daemon->priv->map_native_path_to_device, native_path);
if (device != NULL) {
device = devkit_disks_device_new (daemon, native_path);
if (device != NULL) {
- /* update whether device is mounted */
- l = g_list_prepend (NULL, device);
- update_mount_state (daemon, l);
- g_list_free (l);
-
/* only take a weak ref; the device will stay on the bus until
* it's unreffed. So if we ref it, it'll never go away. Stupid
* dbus-glib, no cookie for you.
GList *devices;
devices = g_hash_table_get_values (daemon->priv->map_native_path_to_device);
- update_mount_state (daemon, devices);
+ devkit_disks_daemon_local_update_mount_state (daemon, devices, TRUE);
g_list_free (devices);
}
gpointer hook_user_data,
DBusGMethodInvocation *context);
+static void force_unmount (DevkitDisksDevice *device, gboolean remove_dir_on_unmount);
+
enum
{
PROP_0,
char *path;
GDir *dir;
const char *name;
+ GList *l;
ret = FALSE;
info = NULL;
update_slaves (device);
+ /* update whether device is mounted */
+ l = g_list_prepend (NULL, device);
+ devkit_disks_daemon_local_update_mount_state (device->priv->daemon, l, FALSE);
+ g_list_free (l);
+
ret = TRUE;
out:
devkit_disks_device_removed (DevkitDisksDevice *device)
{
update_slaves (device);
+
+ /* if this device was mounted by us, then forcibly unmount it
+ *
+ * This is the normally the path where the enclosing device is
+ * removed. Compare with devkit_disks_device_changed() for the
+ * other path.
+ */
+ if (device->priv->info.device_is_mounted && device->priv->info.device_mount_path != NULL) {
+ gboolean remove_dir_on_unmount;
+ if (mounts_file_has_device (device, NULL, &remove_dir_on_unmount)) {
+ g_warning ("Force unmounting device %s", device->priv->info.device_file);
+ force_unmount (device, remove_dir_on_unmount);
+ }
+ }
}
DevkitDisksDevice *
/* TODO: fix up update_info to return TRUE iff something has changed */
if (update_info (device))
emit_changed (device);
+
+ /* Check if media was removed. If so, we need to forcibly unmount the device
+ * or all the partitions of the device
+ *
+ * This is the normally the path where the media is removed but the enclosing
+ * device is still present. Compare with devkit_disks_device_removed() for
+ * the other path.
+ */
+ if (!device->priv->info.device_is_media_available) {
+ gboolean remove_dir_on_unmount;
+
+ if (device->priv->info.device_is_mounted && device->priv->info.device_mount_path != NULL) {
+ if (mounts_file_has_device (device, NULL, &remove_dir_on_unmount)) {
+ g_warning ("Force unmounting device %s", device->priv->info.device_file);
+ force_unmount (device, remove_dir_on_unmount);
+ }
+ } else {
+ GList *l;
+ GList *devices;
+
+ /* check all partitions */
+ devices = devkit_disks_daemon_local_get_all_devices (device->priv->daemon);
+ for (l = devices; l != NULL; l = l->next) {
+ DevkitDisksDevice *d = DEVKIT_DISKS_DEVICE (l->data);
+
+ if (d->priv->info.device_is_partition &&
+ d->priv->info.partition_slave != NULL &&
+ strcmp (d->priv->info.partition_slave, device->priv->object_path) == 0) {
+
+ if (d->priv->info.device_is_mounted &&
+ d->priv->info.device_mount_path != NULL) {
+ if (mounts_file_has_device (d, NULL, &remove_dir_on_unmount)) {
+ g_warning ("Force unmounting device %s",
+ d->priv->info.device_file);
+ force_unmount (d, remove_dir_on_unmount);
+ }
+ }
+
+ }
+ } /* for all devices */
+ }
+ }
}
/*--------------------------------------------------------------------------------------------------------------*/
}
void
-devkit_disks_device_local_set_mounted (DevkitDisksDevice *device, const char *mount_path)
+devkit_disks_device_local_set_mounted (DevkitDisksDevice *device,
+ const char *mount_path,
+ gboolean emit_changed_signal)
{
g_free (device->priv->info.device_mount_path);
device->priv->info.device_mount_path = g_strdup (mount_path);
device->priv->info.device_is_mounted = TRUE;
- emit_changed (device);
+ if (emit_changed_signal)
+ emit_changed (device);
}
void
-devkit_disks_device_local_set_unmounted (DevkitDisksDevice *device)
+devkit_disks_device_local_set_unmounted (DevkitDisksDevice *device,
+ gboolean emit_changed_signal)
{
char *mount_path;
gboolean remove_dir_on_unmount;
}
}
- emit_changed (device);
+ if (emit_changed_signal)
+ emit_changed (device);
g_free (mount_path);
}
if (WEXITSTATUS (status) == 0 && !job_was_cancelled) {
if (!data->is_remount) {
- devkit_disks_device_local_set_mounted (device, data->mount_point);
+ devkit_disks_device_local_set_mounted (device, data->mount_point, TRUE);
mounts_file_add (device, uid, data->remove_dir_on_unmount);
}
dbus_g_method_return (context, data->mount_point);
char *mount_path = user_data;
if (WEXITSTATUS (status) == 0 && !job_was_cancelled) {
- devkit_disks_device_local_set_unmounted (device);
+ devkit_disks_device_local_set_unmounted (device, TRUE);
mounts_file_remove (device, mount_path);
dbus_g_method_return (context);
} else {
}
/*--------------------------------------------------------------------------------------------------------------*/
+
+static void
+force_unmount_completed_cb (DBusGMethodInvocation *context,
+ DevkitDisksDevice *device,
+ PolKitCaller *pk_caller,
+ gboolean job_was_cancelled,
+ int status,
+ const char *stderr,
+ const char *stdout,
+ gpointer user_data)
+{
+ const char *mount_path = user_data;
+ char *touch_str;
+
+ if (WEXITSTATUS (status) == 0 && !job_was_cancelled) {
+
+ g_warning ("Successfully force unmounted device %s", device->priv->info.device_file);
+ devkit_disks_device_local_set_unmounted (device, TRUE);
+ mounts_file_remove (device, mount_path);
+
+ /* TODO: when we add polling, this can probably be removed. I have no idea why hal's
+ * poller don't cause the kernel to revalidate the (missing) media
+ */
+ touch_str = g_strdup_printf ("touch %s", device->priv->info.device_file);
+ g_spawn_command_line_async (touch_str, NULL);
+ g_free (touch_str);
+ } else {
+ g_warning ("force unmount failed: %s", stderr);
+ }
+}
+
+static void
+force_unmount (DevkitDisksDevice *device, gboolean remove_dir_on_unmount)
+{
+ int n;
+ char *argv[16];
+ GError *error;
+
+ n = 0;
+ argv[n++] = "umount";
+ /* on Linux, we only have lazy unmount for now */
+ argv[n++] = "-l";
+ argv[n++] = device->priv->info.device_mount_path;
+ argv[n++] = NULL;
+
+ error = NULL;
+ if (!job_new (NULL,
+ "ForceUnmount",
+ FALSE,
+ device,
+ NULL,
+ argv,
+ NULL,
+ force_unmount_completed_cb,
+ g_strdup (device->priv->info.device_mount_path),
+ g_free)) {
+ g_warning ("Couldn't spawn unmount for force unmounting: %s", error->message);
+ g_error_free (error);
+ }
+}
+
+/*--------------------------------------------------------------------------------------------------------------*/
/* local methods */
-const char *devkit_disks_device_local_get_object_path (DevkitDisksDevice *device);
-const char *devkit_disks_device_local_get_native_path (DevkitDisksDevice *device);
+const char *devkit_disks_device_local_get_object_path (DevkitDisksDevice *device);
+const char *devkit_disks_device_local_get_native_path (DevkitDisksDevice *device);
-const char *devkit_disks_device_local_get_device_file (DevkitDisksDevice *device);
-const char *devkit_disks_device_local_get_mount_path (DevkitDisksDevice *device);
+const char *devkit_disks_device_local_get_device_file (DevkitDisksDevice *device);
+const char *devkit_disks_device_local_get_mount_path (DevkitDisksDevice *device);
-void devkit_disks_device_local_set_mounted (DevkitDisksDevice *device, const char *mount_path);
-void devkit_disks_device_local_set_unmounted (DevkitDisksDevice *device);
+void devkit_disks_device_local_set_mounted (DevkitDisksDevice *device,
+ const char *mount_path,
+ gboolean emit_changed_signal);
+void devkit_disks_device_local_set_unmounted (DevkitDisksDevice *device,
+ gboolean emit_changed_signal);
-gboolean devkit_disks_device_local_is_busy (DevkitDisksDevice *device);
+gboolean devkit_disks_device_local_is_busy (DevkitDisksDevice *device);
gboolean devkit_disks_device_local_partitions_are_busy (DevkitDisksDevice *device);
/* exported methods */