1 /*
2  *      g-udisks-volume-monitor.c
3  *
4  *      Copyright 2010 PCMan <pcman.tw@gmail.com>
5  *
6  *      This program is free software; you can redistribute it and/or modify
7  *      it under the terms of the GNU General Public License as published by
8  *      the Free Software Foundation; either version 2 of the License, or
9  *      (at your option) any later version.
10  *
11  *      This program is distributed in the hope that it will be useful,
12  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *      GNU General Public License for more details.
15  *
16  *      You should have received a copy of the GNU General Public License
17  *      along with this program; if not, write to the Free Software
18  *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *      MA 02110-1301, USA.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 
26 #include "dbus-utils.h"
27 #include "udisks.h"
28 
29 #include "g-udisks-volume-monitor.h"
30 #include "g-udisks-device.h"
31 #include "g-udisks-drive.h"
32 #include "g-udisks-volume.h"
33 
34 /* FIXME: later we need to remove this when gio-udisks becomes an
35  * independent gio module. */
36 #include "fm-config.h"
37 
38 static guint sig_drive_changed;
39 static guint sig_drive_connected;
40 static guint sig_drive_disconnected;
41 static guint sig_drive_eject_button;
42 static guint sig_mount_added;
43 static guint sig_mount_changed;
44 static guint sig_mount_premount;
45 static guint sig_mount_removed;
46 static guint sig_volume_added;
47 static guint sig_volume_changed;
48 static guint sig_volume_removed;
49 
50 static void g_udisks_device_added(GUDisksDevice* dev, GUDisksVolumeMonitor* mon);
51 static void g_udisks_device_changed(GUDisksDevice* dev, GUDisksVolumeMonitor* mon);
52 static void g_udisks_device_removed(GUDisksDevice* dev, GUDisksVolumeMonitor* mon);
53 
54 typedef void (*GUDisksDeviceEventHandler)(GUDisksDevice*, GUDisksVolumeMonitor*);
55 
56 typedef struct
57 {
58     GUDisksDevice* dev;
59     GUDisksDeviceEventHandler func;
60 }QueuedEvent;
61 
62 static void g_udisks_volume_monitor_finalize            (GObject *object);
63 static GMount* get_mount_for_mount_path(const char *mount_path, GCancellable *cancellable);
64 
65 static gboolean is_supported(void);
66 static GList* get_connected_drives(GVolumeMonitor *mon);
67 static GList* get_volumes(GVolumeMonitor *mon);
68 static GList* get_mounts(GVolumeMonitor *mon);
69 static GVolume *get_volume_for_uuid(GVolumeMonitor *mon, const char *uuid);
70 static GMount *get_mount_for_uuid(GVolumeMonitor *mon, const char *uuid);
71 static void drive_eject_button(GVolumeMonitor *mon, GDrive *drive);
72 
73 static void add_device(GUDisksVolumeMonitor* mon, DBusGProxy* proxy, const char* obj_path, gboolean emit_signal);
74 static void on_device_added(DBusGProxy* proxy, const char* obj_path, gpointer user_data);
75 static void on_device_removed(DBusGProxy* proxy, const char* obj_path, gpointer user_data);
76 static void on_device_changed(DBusGProxy* proxy, const char* obj_path, gpointer user_data);
77 
78 static GList* find_device_l(GUDisksVolumeMonitor* mon, const char* obj_path);
79 static GList* find_drive_l(GUDisksVolumeMonitor* mon, GUDisksDevice* dev);
80 static GList* find_volume_l(GUDisksVolumeMonitor* mon, GUDisksDevice* dev);
81 
find_device(GUDisksVolumeMonitor * mon,const char * obj_path)82 static inline GUDisksDevice* find_device(GUDisksVolumeMonitor* mon, const char* obj_path)
83 {
84     GList* l = find_device_l(mon, obj_path);
85     return l ? G_UDISKS_DEVICE(l->data) : NULL;
86 }
87 
find_drive(GUDisksVolumeMonitor * mon,GUDisksDevice * dev)88 static inline GUDisksDrive* find_drive(GUDisksVolumeMonitor* mon, GUDisksDevice* dev)
89 {
90     GList* l = find_drive_l(mon, dev);
91     return l ? G_UDISKS_DRIVE(l->data) : NULL;
92 }
93 
find_volume(GUDisksVolumeMonitor * mon,GUDisksDevice * dev)94 static inline GUDisksVolume* find_volume(GUDisksVolumeMonitor* mon, GUDisksDevice* dev)
95 {
96     GList* l = find_volume_l(mon, dev);
97     return l ? G_UDISKS_VOLUME(l->data) : NULL;
98 }
99 
100 
101 G_DEFINE_TYPE(GUDisksVolumeMonitor, g_udisks_volume_monitor, G_TYPE_NATIVE_VOLUME_MONITOR);
102 
103 
g_udisks_volume_monitor_class_init(GUDisksVolumeMonitorClass * klass)104 static void g_udisks_volume_monitor_class_init(GUDisksVolumeMonitorClass *klass)
105 {
106     GObjectClass *g_object_class = G_OBJECT_CLASS(klass);
107     GNativeVolumeMonitorClass *parent_class = G_NATIVE_VOLUME_MONITOR_CLASS(klass);
108     GVolumeMonitorClass *monitor_class = G_VOLUME_MONITOR_CLASS (klass);
109 
110     g_object_class->finalize = g_udisks_volume_monitor_finalize;
111     parent_class->get_mount_for_mount_path = get_mount_for_mount_path;
112 
113     monitor_class->get_mounts = get_mounts;
114     monitor_class->get_volumes = get_volumes;
115     monitor_class->get_connected_drives = get_connected_drives;
116     monitor_class->get_volume_for_uuid = get_volume_for_uuid;
117     monitor_class->get_mount_for_uuid = get_mount_for_uuid;
118     monitor_class->is_supported = is_supported;
119     monitor_class->drive_eject_button = drive_eject_button;
120 
121     sig_drive_changed = g_signal_lookup("drive-changed", G_TYPE_VOLUME_MONITOR);
122     sig_drive_connected = g_signal_lookup("drive-connected", G_TYPE_VOLUME_MONITOR);
123     sig_drive_disconnected = g_signal_lookup("drive-disconnected", G_TYPE_VOLUME_MONITOR);
124     sig_drive_eject_button = g_signal_lookup("drive-eject-button", G_TYPE_VOLUME_MONITOR);
125     sig_mount_added = g_signal_lookup("mount-added", G_TYPE_VOLUME_MONITOR);
126     sig_mount_changed = g_signal_lookup("mount-changed", G_TYPE_VOLUME_MONITOR);
127     sig_mount_premount = g_signal_lookup("mount-premount", G_TYPE_VOLUME_MONITOR);
128     sig_mount_removed = g_signal_lookup("mount-removed", G_TYPE_VOLUME_MONITOR);
129     sig_volume_added = g_signal_lookup("volume-added", G_TYPE_VOLUME_MONITOR);
130     sig_volume_changed = g_signal_lookup("volume-changed", G_TYPE_VOLUME_MONITOR);
131     sig_volume_removed = g_signal_lookup("volume-removed", G_TYPE_VOLUME_MONITOR);
132 }
133 
134 
g_udisks_volume_monitor_finalize(GObject * object)135 static void g_udisks_volume_monitor_finalize(GObject *object)
136 {
137     GUDisksVolumeMonitor *self;
138 
139     g_return_if_fail(object != NULL);
140     g_return_if_fail(G_IS_UDISKS_VOLUME_MONITOR(object));
141 
142     self = G_UDISKS_VOLUME_MONITOR(object);
143 
144     if(self->idle_handler)
145     {
146         GList* l;
147         g_source_remove(self->idle_handler);
148         for(l = self->queued_events; l; l=l->next)
149         {
150             QueuedEvent* q = (QueuedEvent*)l->data;
151             g_object_unref(q->dev);
152             g_slice_free(QueuedEvent, q);
153         }
154         g_list_free(self->queued_events);
155     }
156 
157     if(self->udisks_proxy)
158     {
159         dbus_g_proxy_disconnect_signal(self->udisks_proxy, "DeviceAdded", G_CALLBACK(on_device_added), self);
160         dbus_g_proxy_disconnect_signal(self->udisks_proxy, "DeviceRemoved", G_CALLBACK(on_device_removed), self);
161         dbus_g_proxy_disconnect_signal(self->udisks_proxy, "DeviceChanged", G_CALLBACK(on_device_changed), self);
162         g_object_unref(self->udisks_proxy);
163     }
164 
165     if(self->devices)
166     {
167         g_list_foreach(self->devices, (GFunc)g_object_unref, NULL);
168         g_list_free(self->devices);
169     }
170 
171     if(self->drives)
172     {
173         g_list_foreach(self->drives, (GFunc)g_object_unref, NULL);
174         g_list_free(self->drives);
175     }
176 
177     if(self->volumes)
178     {
179         g_list_foreach(self->volumes, (GFunc)g_object_unref, NULL);
180         g_list_free(self->volumes);
181     }
182 
183     G_OBJECT_CLASS(g_udisks_volume_monitor_parent_class)->finalize(object);
184 }
185 
update_volume_drive(GUDisksVolume * vol,GUDisksVolumeMonitor * mon)186 static void update_volume_drive(GUDisksVolume* vol, GUDisksVolumeMonitor* mon)
187 {
188     /* set association between drive and volumes here */
189     GUDisksDevice* dev;
190     if(vol->dev->is_drive) /* it's a drive itself (cdrom is an example) */
191         dev = vol->dev;
192     else if(vol->dev->partition_slave)
193         dev = find_device(mon, vol->dev->partition_slave);
194     else
195         dev = NULL;
196 
197     /* no ref_count handling is needed. volume manager owns all the objects. */
198     if(dev)
199     {
200         GUDisksDrive* drv = find_drive(mon, dev);
201         vol->drive = drv;
202     }
203     else
204         vol->drive = NULL;
205 }
206 
g_udisks_volume_monitor_init(GUDisksVolumeMonitor * self)207 static void g_udisks_volume_monitor_init(GUDisksVolumeMonitor *self)
208 {
209     self->con = dbus_g_bus_get(DBUS_BUS_SYSTEM, NULL);
210     if(self->con)
211     {
212         GPtrArray* ret;
213         /* FIXME: handle disconnecting from dbus */
214         self->udisks_proxy = dbus_g_proxy_new_for_name(self->con, "org.freedesktop.UDisks", "/org/freedesktop/UDisks", "org.freedesktop.UDisks");
215 
216         if(org_freedesktop_UDisks_enumerate_devices(self->udisks_proxy, &ret, NULL))
217         {
218             guint i;
219             char** paths = (char**)ret->pdata;
220             for(i=0; i<ret->len;++i)
221                 add_device(self, self->udisks_proxy, paths[i], FALSE);
222             g_ptr_array_free(ret, TRUE);
223         }
224 
225         dbus_g_proxy_add_signal(self->udisks_proxy, "DeviceAdded", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
226         dbus_g_proxy_add_signal(self->udisks_proxy, "DeviceRemoved", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
227         dbus_g_proxy_add_signal(self->udisks_proxy, "DeviceChanged", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
228 
229         dbus_g_proxy_connect_signal(self->udisks_proxy, "DeviceAdded", G_CALLBACK(on_device_added), self, NULL);
230         dbus_g_proxy_connect_signal(self->udisks_proxy, "DeviceRemoved", G_CALLBACK(on_device_removed), self, NULL);
231         dbus_g_proxy_connect_signal(self->udisks_proxy, "DeviceChanged", G_CALLBACK(on_device_changed), self, NULL);
232 
233         /* find drives for volumes */
234         if(self->volumes && self->drives)
235             g_list_foreach(self->volumes, (GFunc)update_volume_drive, self);
236     }
237 }
238 
239 
g_udisks_volume_monitor_new(void)240 GNativeVolumeMonitor *g_udisks_volume_monitor_new(void)
241 {
242     return g_object_new(G_UDISKS_VOLUME_MONITOR_TYPE, NULL);
243 }
244 
get_mount_for_mount_path(const char * mount_path,GCancellable * cancellable)245 GMount* get_mount_for_mount_path(const char *mount_path, GCancellable *cancellable)
246 {
247     /* TODO */
248 
249     return NULL;
250 }
251 
252 
is_supported(void)253 gboolean is_supported(void)
254 {
255     return TRUE;
256 }
257 
get_connected_drives(GVolumeMonitor * mon)258 GList* get_connected_drives(GVolumeMonitor *mon)
259 {
260     GUDisksVolumeMonitor* umon = G_UDISKS_VOLUME_MONITOR(mon);
261     GList* drvs = g_list_copy(umon->drives);
262     g_list_foreach(drvs, (GFunc)g_object_ref, NULL);
263     return drvs;
264 }
265 
get_volumes(GVolumeMonitor * mon)266 GList* get_volumes(GVolumeMonitor *mon)
267 {
268     GUDisksVolumeMonitor* umon = G_UDISKS_VOLUME_MONITOR(mon);
269     GList* vols = g_list_copy(umon->volumes);
270     g_list_foreach(vols, (GFunc)g_object_ref, NULL);
271     return vols;
272 }
273 
get_mounts(GVolumeMonitor * mon)274 GList* get_mounts(GVolumeMonitor *mon)
275 {
276     GUDisksVolumeMonitor* umon = G_UDISKS_VOLUME_MONITOR(mon);
277     GList* l;
278     GList* mnts = NULL;
279     for(l = umon->volumes; l; l=l->next)
280     {
281         GUDisksVolume* vol = G_UDISKS_VOLUME(l->data);
282         if(vol->mount)
283             mnts = g_list_prepend(mnts, g_object_ref(vol->mount));
284     }
285     return mnts;
286 }
287 
get_volume_for_uuid(GVolumeMonitor * mon,const char * uuid)288 GVolume *get_volume_for_uuid(GVolumeMonitor *mon, const char *uuid)
289 {
290     GUDisksVolumeMonitor* umon = G_UDISKS_VOLUME_MONITOR(mon);
291     GList* l;
292     for(l = umon->volumes; l; l=l->next)
293     {
294         GUDisksVolume* vol = G_UDISKS_VOLUME(l->data);
295         if(g_strcmp0(vol->dev->uuid, uuid) == 0)
296             return (GVolume*)g_object_ref(vol);
297     }
298     return NULL;
299 }
300 
get_mount_for_uuid(GVolumeMonitor * mon,const char * uuid)301 GMount *get_mount_for_uuid(GVolumeMonitor *mon, const char *uuid)
302 {
303     GUDisksVolumeMonitor* umon = G_UDISKS_VOLUME_MONITOR(mon);
304     GList* l;
305     for(l = umon->volumes; l; l=l->next)
306     {
307         GUDisksVolume* vol = G_UDISKS_VOLUME(l->data);
308         if(g_strcmp0(vol->dev->uuid, uuid) == 0)
309             return g_volume_get_mount(G_VOLUME(vol));
310     }
311     return NULL;
312 }
313 
314 /* signal added in 2.17 */
drive_eject_button(GVolumeMonitor * mon,GDrive * drive)315 void drive_eject_button(GVolumeMonitor *mon, GDrive *drive)
316 {
317     /* TODO */
318     //GUDisksVolumeMonitor* umon = G_UDISKS_VOLUME_MONITOR(mon);
319 
320 }
321 
find_device_l(GUDisksVolumeMonitor * mon,const char * obj_path)322 GList* find_device_l(GUDisksVolumeMonitor* mon, const char* obj_path)
323 {
324     GList* l;
325     for(l = mon->devices; l; l=l->next)
326     {
327         GUDisksDevice* dev = G_UDISKS_DEVICE(l->data);
328         if(g_strcmp0(dev->obj_path, obj_path) == 0)
329             return l;
330     }
331     return NULL;
332 }
333 
find_drive_l(GUDisksVolumeMonitor * mon,GUDisksDevice * dev)334 GList* find_drive_l(GUDisksVolumeMonitor* mon, GUDisksDevice* dev)
335 {
336     GList* l;
337     for(l = mon->drives; l; l=l->next)
338     {
339         GUDisksDrive* drv = G_UDISKS_DRIVE(l->data);
340         if(G_UNLIKELY(drv->dev == dev))
341             return l;
342     }
343     return NULL;
344 }
345 
find_volume_l(GUDisksVolumeMonitor * mon,GUDisksDevice * dev)346 GList* find_volume_l(GUDisksVolumeMonitor* mon, GUDisksDevice* dev)
347 {
348     GList* l;
349     for(l = mon->volumes; l; l=l->next)
350     {
351         GUDisksVolume* vol = G_UDISKS_VOLUME(l->data);
352         if(G_UNLIKELY(vol->dev == dev))
353             return l;
354     }
355     return NULL;
356 }
357 
add_drive(GUDisksVolumeMonitor * mon,GUDisksDevice * dev,gboolean emit_signal)358 static void add_drive(GUDisksVolumeMonitor* mon, GUDisksDevice* dev, gboolean emit_signal)
359 {
360     if(!find_drive(mon, dev))
361     {
362         GUDisksDrive* drv = g_udisks_drive_new(mon, dev);
363         mon->drives = g_list_prepend(mon->drives, drv);
364         if(emit_signal)
365             g_signal_emit(mon, sig_drive_connected, 0, drv);
366     }
367 }
368 
add_volume(GUDisksVolumeMonitor * mon,GUDisksDevice * dev,gboolean emit_signal)369 static void add_volume(GUDisksVolumeMonitor* mon, GUDisksDevice* dev, gboolean emit_signal)
370 {
371     if(!find_volume(mon, dev))
372     {
373         GUDisksVolume* vol = g_udisks_volume_new(mon, dev);
374         mon->volumes = g_list_prepend(mon->volumes, vol);
375         if(emit_signal)
376             g_signal_emit(mon, sig_volume_added, 0, vol);
377     }
378 }
379 
remove_drive(GUDisksVolumeMonitor * mon,GUDisksDevice * dev)380 static void remove_drive(GUDisksVolumeMonitor* mon, GUDisksDevice* dev)
381 {
382     GList* l = find_drive_l(mon, dev);
383     if(l)
384     {
385         GUDisksDrive* drv = G_UDISKS_DRIVE(l->data);
386         mon->drives = g_list_delete_link(mon->drives, l);
387         g_signal_emit(mon, sig_drive_disconnected, 0, drv);
388         g_udisks_drive_disconnected(drv);
389         drv->mon = NULL;
390         for(l = mon->volumes; l; l=l->next)
391         {
392             GUDisksVolume* vol = G_UDISKS_VOLUME(l->data);
393             if(vol->drive == drv)
394             {
395                 vol->drive = NULL;
396                 /* FIXME: emit sigal for volume change */
397             }
398         }
399         g_object_unref(drv);
400     }
401 }
402 
remove_volume(GUDisksVolumeMonitor * mon,GUDisksDevice * dev)403 static void remove_volume(GUDisksVolumeMonitor* mon, GUDisksDevice* dev)
404 {
405     GList* l = find_volume_l(mon, dev);
406     if(l)
407     {
408         GUDisksVolume* vol = G_UDISKS_VOLUME(l->data);
409         mon->volumes = g_list_delete_link(mon->volumes, l);
410         g_signal_emit(mon, sig_volume_removed, 0, vol);
411         g_udisks_volume_removed(vol);
412         vol->mon = NULL;
413         vol->drive = NULL;
414         g_object_unref(vol);
415     }
416 }
417 
_g_udisks_device_added(GUDisksDevice * dev,GUDisksVolumeMonitor * mon,gboolean emit_signal)418 static void _g_udisks_device_added(GUDisksDevice* dev, GUDisksVolumeMonitor* mon, gboolean emit_signal)
419 {
420     /* FIXME: how should we treat sys internal devices?
421      * make this optional */
422     if(!dev->is_hidden && (!dev->is_sys_internal || fm_config->show_internal_volumes) )
423     {
424         if(dev->is_drive)
425             add_drive(mon, dev, emit_signal);
426 
427         if(g_udisks_device_is_volume(dev))
428             add_volume(mon, dev, emit_signal);
429     }
430 }
431 
g_udisks_device_added(GUDisksDevice * dev,GUDisksVolumeMonitor * mon)432 static void g_udisks_device_added(GUDisksDevice* dev, GUDisksVolumeMonitor* mon)
433 {
434     g_debug("g_udisks_device_added");
435     _g_udisks_device_added(dev, mon, TRUE);
436 }
437 
g_udisks_device_changed(GUDisksDevice * dev,GUDisksVolumeMonitor * mon)438 static void g_udisks_device_changed(GUDisksDevice* dev, GUDisksVolumeMonitor* mon)
439 {
440     GUDisksDrive* drv = find_drive(mon, dev);
441     GUDisksVolume* vol = find_volume(mon, dev);
442     /*
443     gboolean is_drive = dev->is_drive;
444     char* usage = g_strdup(dev->usage);
445     */
446     g_debug("g_udisks_device_changed");
447     if(drv)
448     {
449         g_signal_emit(mon, sig_drive_changed, 0, drv);
450         g_udisks_drive_changed(drv);
451         /* it's no longer a drive */
452         if(!dev->is_drive)
453             remove_drive(mon, dev);
454     }
455     else
456     {
457         if(dev->is_drive)
458             add_drive(mon, dev, TRUE);
459     }
460 
461     if(vol)
462     {
463         update_volume_drive(vol, mon);
464         g_signal_emit(mon, sig_volume_changed, 0, vol);
465         g_udisks_volume_changed(vol);
466 
467         /* it's no longer a volume */
468         if(!g_udisks_device_is_volume(dev))
469             remove_volume(mon, dev);
470     }
471     else
472     {
473         /* we got a usable volume now */
474         if(g_udisks_device_is_volume(dev))
475             add_volume(mon, dev, TRUE);
476     }
477 }
478 
g_udisks_device_removed(GUDisksDevice * dev,GUDisksVolumeMonitor * mon)479 static void g_udisks_device_removed(GUDisksDevice* dev, GUDisksVolumeMonitor* mon)
480 {
481     g_debug("g_udisks_device_removed");
482 
483     if(dev->is_drive)
484         remove_drive(mon, dev);
485 
486     remove_volume(mon, dev);
487 }
488 
on_idle(GUDisksVolumeMonitor * mon)489 static gboolean on_idle(GUDisksVolumeMonitor* mon)
490 {
491     GList* l;
492     g_debug("on_idle: %d", g_list_length(mon->queued_events));
493     for(l = mon->queued_events; l; l=l->next)
494     {
495         QueuedEvent* q = (QueuedEvent*)l->data;
496         q->func(q->dev, mon);
497         g_object_unref(q->dev);
498         g_slice_free(QueuedEvent, q);
499     }
500     g_list_free(mon->queued_events);
501     mon->queued_events = NULL;
502     mon->idle_handler = 0;
503     return FALSE;
504 }
505 
g_udisks_device_queue_event(GUDisksDevice * dev,GUDisksDeviceEventHandler func,GUDisksVolumeMonitor * mon)506 static void g_udisks_device_queue_event(GUDisksDevice* dev, GUDisksDeviceEventHandler func, GUDisksVolumeMonitor* mon)
507 {
508     QueuedEvent* q = g_slice_new(QueuedEvent);
509     q->dev = g_object_ref(dev);
510     q->func = func;
511     mon->queued_events = g_list_append(mon->queued_events, q);
512 
513     if(0 == mon->idle_handler)
514         mon->idle_handler = g_idle_add_full(G_PRIORITY_HIGH, (GSourceFunc)on_idle, mon, NULL);
515 }
516 
add_device(GUDisksVolumeMonitor * mon,DBusGProxy * proxy,const char * obj_path,gboolean emit_signal)517 static void add_device(GUDisksVolumeMonitor* mon, DBusGProxy* proxy, const char* obj_path, gboolean emit_signal)
518 {
519     if(!find_device(mon, obj_path))
520     {
521         DBusGProxy *dev_proxy = dbus_g_proxy_new_for_name(mon->con,
522                                             "org.freedesktop.UDisks",
523                                             obj_path,
524                                             "org.freedesktop.DBus.Properties");
525         GError* err = NULL;
526         GHashTable* props = dbus_get_all_props(dev_proxy, "org.freedesktop.UDisks.Device", &err);
527         if(props)
528         {
529             GUDisksDevice* dev = g_udisks_device_new(obj_path, props);
530             g_hash_table_destroy(props);
531 
532             mon->devices = g_list_prepend(mon->devices, dev);
533             if(emit_signal)
534                 g_udisks_device_queue_event(dev, g_udisks_device_added, mon);
535             else
536                 _g_udisks_device_added(dev, mon, FALSE);
537         }
538         else
539         {
540             g_debug("%s", err->message);
541             g_error_free(err);
542         }
543         g_object_unref(dev_proxy);
544     }
545     g_debug("device_added: %s", obj_path);
546 }
547 
on_device_added(DBusGProxy * proxy,const char * obj_path,gpointer user_data)548 void on_device_added(DBusGProxy* proxy, const char* obj_path, gpointer user_data)
549 {
550     GUDisksVolumeMonitor* mon = G_UDISKS_VOLUME_MONITOR(user_data);
551     add_device(mon, proxy, obj_path, TRUE);
552 }
553 
554 
on_device_removed(DBusGProxy * proxy,const char * obj_path,gpointer user_data)555 void on_device_removed(DBusGProxy* proxy, const char* obj_path, gpointer user_data)
556 {
557     GUDisksVolumeMonitor* mon = G_UDISKS_VOLUME_MONITOR(user_data);
558     GList* l;
559     l = find_device_l(mon, obj_path);
560     if(l)
561     {
562         GUDisksDevice* dev = G_UDISKS_DEVICE(l->data);
563         mon->devices = g_list_delete_link(mon->devices, l);
564 
565         g_udisks_device_queue_event(dev, g_udisks_device_removed, mon);
566         g_object_unref(dev);
567     }
568     g_debug("device_removed: %s", obj_path);
569 
570 }
571 
on_device_changed(DBusGProxy * proxy,const char * obj_path,gpointer user_data)572 void on_device_changed(DBusGProxy* proxy, const char* obj_path, gpointer user_data)
573 {
574     GUDisksVolumeMonitor* mon = G_UDISKS_VOLUME_MONITOR(user_data);
575     GUDisksDevice* dev = find_device(mon, obj_path);
576     if(dev)
577     {
578         DBusGProxy *dev_proxy = dbus_g_proxy_new_for_name(mon->con,
579                                             "org.freedesktop.UDisks",
580                                             obj_path,
581                                             "org.freedesktop.DBus.Properties");
582 
583         GError* err = NULL;
584         GHashTable* props = dbus_get_all_props(dev_proxy, "org.freedesktop.UDisks.Device", &err);
585         if(props)
586         {
587             g_udisks_device_update(dev, props);
588             g_hash_table_destroy(props);
589 
590             g_udisks_device_queue_event(dev, g_udisks_device_changed, mon);
591         }
592         g_object_unref(dev_proxy);
593     }
594     g_debug("device_changed: %s", obj_path);
595 }
596 
597