1 #include "config.h"
2 
3 #include "e_fm_shared_device.h"
4 #include "e_fm_shared_codec.h"
5 #include "e_fm_ipc.h"
6 
7 #include "e_macros.h"
8 #include "e_fm_main_udisks.h"
9 #include "e_fm_main.h"
10 
11 #define E_TYPEDEFS
12 #include "e_fm_op.h"
13 
14 #define UDISKS_BUS "org.freedesktop.UDisks"
15 #define UDISKS_PATH "/org/freedesktop/UDisks"
16 #define UDISKS_INTERFACE "org.freedesktop.UDisks"
17 #define UDISKS_DEVICE_INTERFACE "org.freedesktop.UDisks.Device"
18 
19 static Eldbus_Connection *_e_fm_main_udisks_conn = NULL;
20 static Eldbus_Proxy *_e_fm_main_udisks_proxy = NULL;
21 static Eina_List *_e_stores = NULL;
22 static Eina_List *_e_vols = NULL;
23 
24 static void _e_fm_main_udisks_cb_dev_all(void *data, const Eldbus_Message *msg,
25                                          Eldbus_Pending *pending);
26 static void _e_fm_main_udisks_cb_dev_verify(void *data, const Eldbus_Message *msg,
27                                             Eldbus_Pending *pending);
28 static void _e_fm_main_udisks_cb_dev_add(void *data, const Eldbus_Message *msg);
29 static void _e_fm_main_udisks_cb_dev_del(void *data, const Eldbus_Message *msg);
30 static void _e_fm_main_udisks_cb_prop_modified(void *data, const Eldbus_Message *msg);
31 static void _e_fm_main_udisks_cb_store_prop(void *data, const Eldbus_Message *msg,
32                                             Eldbus_Pending *pending);
33 static void _e_fm_main_udisks_cb_vol_prop(void *data, const Eldbus_Message *msg,
34                                           Eldbus_Pending *pending);
35 static void _e_fm_main_udisks_cb_vol_mounted(E_Volume *v);
36 static void _e_fm_main_udisks_cb_vol_unmounted(E_Volume *v);
37 static void _e_fm_main_udisks_cb_vol_unmounted_before_eject(E_Volume *v);
38 
39 static Eina_Bool _e_fm_main_udisks_cb_vol_ejecting_after_unmount(E_Volume *v);
40 static void      _e_fm_main_udisks_cb_vol_ejected(E_Volume *v);
41 static int _e_fm_main_udisks_format_error_msg(char     **buf,
42                                               E_Volume  *v,
43                                               const char *name,
44                                               const char *message);
45 
46 static Eina_Bool _e_fm_main_udisks_vol_mount_timeout(E_Volume *v);
47 static Eina_Bool _e_fm_main_udisks_vol_unmount_timeout(E_Volume *v);
48 static Eina_Bool _e_fm_main_udisks_vol_eject_timeout(E_Volume *v);
49 static E_Storage *_storage_find_by_dbus_path(const char *path);
50 static E_Volume *_volume_find_by_dbus_path(const char *path);
51 static void _volume_del(E_Volume *v);
52 
53 static void
_e_fm_main_udisks_name_start(void * data EINA_UNUSED,const Eldbus_Message * msg,Eldbus_Pending * pending EINA_UNUSED)54 _e_fm_main_udisks_name_start(void *data EINA_UNUSED, const Eldbus_Message *msg,
55                              Eldbus_Pending *pending EINA_UNUSED)
56 {
57    unsigned flag = 0;
58    Eldbus_Object *obj;
59 
60    if (!eldbus_message_arguments_get(msg, "u", &flag) || !flag)
61      {
62         _e_fm_main_udisks_catch(EINA_FALSE);
63         return;
64      }
65    obj = eldbus_object_get(_e_fm_main_udisks_conn, UDISKS_BUS, UDISKS_PATH);
66    _e_fm_main_udisks_proxy = eldbus_proxy_get(obj, UDISKS_INTERFACE);
67 
68    eldbus_proxy_call(_e_fm_main_udisks_proxy, "EnumerateDevices",
69                     _e_fm_main_udisks_cb_dev_all, NULL, -1, "");
70 
71    eldbus_proxy_signal_handler_add(_e_fm_main_udisks_proxy, "DeviceAdded",
72                                   _e_fm_main_udisks_cb_dev_add, NULL);
73    eldbus_proxy_signal_handler_add(_e_fm_main_udisks_proxy, "DeviceRemoved",
74                                   _e_fm_main_udisks_cb_dev_del, NULL);
75    _e_fm_main_udisks_catch(EINA_TRUE); /* signal usage of udisks for mounting */
76 }
77 
78 static void
_e_fm_main_udisks_cb_dev_all(void * data EINA_UNUSED,const Eldbus_Message * msg,Eldbus_Pending * pending EINA_UNUSED)79 _e_fm_main_udisks_cb_dev_all(void *data EINA_UNUSED, const Eldbus_Message *msg,
80                              Eldbus_Pending *pending EINA_UNUSED)
81 {
82    const char *name, *txt, *path;
83    Eldbus_Message_Iter *array;
84 
85    if (eldbus_message_error_get(msg, &name, &txt))
86      {
87         ERR("Error %s %s.", name, txt);
88         return;
89      }
90 
91    if (!eldbus_message_arguments_get(msg, "ao", &array))
92      {
93         ERR("Error getting arguments.");
94         return;
95      }
96 
97    while (eldbus_message_iter_get_and_next(array, 'o', &path))
98      {
99         Eldbus_Message *new_msg;
100         new_msg = eldbus_message_method_call_new(UDISKS_BUS, path,
101                                                 ELDBUS_FDO_INTERFACE_PROPERTIES, "Get");
102         eldbus_message_arguments_append(new_msg, "ss", UDISKS_DEVICE_INTERFACE, "IdUsage");
103         eldbus_connection_send(_e_fm_main_udisks_conn, new_msg,
104                               _e_fm_main_udisks_cb_dev_verify,
105                               eina_stringshare_add(path), -1);
106         INF("DB INIT DEV+: %s", path);
107      }
108 }
109 
110 
111 static void
_e_fm_main_udisks_cb_dev_verify(void * data,const Eldbus_Message * msg,Eldbus_Pending * pending EINA_UNUSED)112 _e_fm_main_udisks_cb_dev_verify(void *data, const Eldbus_Message *msg,
113                                 Eldbus_Pending *pending EINA_UNUSED)
114 {
115    const char *name, *txt, *id_usage, *path = data;
116    Eldbus_Message_Iter *variant;
117 
118    if (eldbus_message_error_get(msg, &name, &txt))
119      {
120         ERR("Error %s %s.", name, txt);
121         goto error;
122      }
123 
124    if (!eldbus_message_arguments_get(msg, "v", &variant))
125      {
126         ERR("Error getting arguments.");
127         goto error;
128      }
129 
130    if (!eldbus_message_iter_arguments_get(variant, "s", &id_usage))
131      {
132         ERR("Type of variant not expected");
133         goto error;
134      }
135 
136    if (!id_usage[0])
137      _e_fm_main_udisks_storage_add(path);
138    else if(!strcmp(id_usage, "filesystem"))
139      _e_fm_main_udisks_volume_add(path, EINA_TRUE);
140    else
141      eina_stringshare_del(path);
142    return;
143 error:
144    eina_stringshare_del(path);
145 }
146 
147 static void
_e_fm_main_udisks_cb_dev_verify_added(void * data,const Eldbus_Message * msg,Eldbus_Pending * pending EINA_UNUSED)148 _e_fm_main_udisks_cb_dev_verify_added(void *data, const Eldbus_Message *msg,
149                                 Eldbus_Pending *pending EINA_UNUSED)
150 {
151    const char *name, *txt, *id_usage, *path = data;
152    Eldbus_Message_Iter *variant;
153 
154    if (eldbus_message_error_get(msg, &name, &txt))
155      {
156         ERR("Error %s %s.", name, txt);
157         goto error;
158      }
159 
160    if (!eldbus_message_arguments_get(msg, "v", &variant))
161      {
162         ERR("Error getting arguments.");
163         goto error;
164      }
165 
166    if (!eldbus_message_iter_arguments_get(variant, "s", &id_usage))
167      {
168         ERR("Type of variant not expected");
169         goto error;
170      }
171 
172    DBG("%s usage=%s", path, id_usage);
173    if (!id_usage[0])
174      {
175         E_Storage *s;
176         s = _storage_find_by_dbus_path(path);
177         if (!s)
178           _e_fm_main_udisks_storage_add(path);
179         else
180           eldbus_proxy_property_get_all(s->proxy,
181                                        _e_fm_main_udisks_cb_store_prop, s);
182      }
183    else if(!strcmp(id_usage, "filesystem"))
184      {
185         E_Volume *v;
186         v = _volume_find_by_dbus_path(path);
187         if (!v)
188           _e_fm_main_udisks_volume_add(path, EINA_TRUE);
189         else
190           eldbus_proxy_property_get_all(v->proxy,
191                                        _e_fm_main_udisks_cb_vol_prop, v);
192      }
193    else
194      eina_stringshare_del(path);
195    return;
196 error:
197    eina_stringshare_del(path);
198 }
199 
200 static void
_e_fm_main_udisks_cb_dev_add(void * data EINA_UNUSED,const Eldbus_Message * msg)201 _e_fm_main_udisks_cb_dev_add(void *data EINA_UNUSED, const Eldbus_Message *msg)
202 {
203    Eldbus_Message *new;
204    E_Volume *v;
205    char *path;
206 
207    if (!eldbus_message_arguments_get(msg, "o", &path))
208      return;
209    DBG("DB DEV+: %s", path);
210 
211    v = _volume_find_by_dbus_path(path);
212    if (v)
213      {
214         eldbus_proxy_property_get_all(v->proxy, _e_fm_main_udisks_cb_vol_prop, v);
215         return;
216      }
217 
218    new = eldbus_message_method_call_new(UDISKS_BUS, path, ELDBUS_FDO_INTERFACE_PROPERTIES, "Get");
219    eldbus_message_arguments_append(new, "ss", UDISKS_DEVICE_INTERFACE, "IdUsage");
220    eldbus_connection_send(_e_fm_main_udisks_conn, new,
221                          _e_fm_main_udisks_cb_dev_verify_added,
222                          eina_stringshare_add(path), -1);
223 }
224 
225 static void
_e_fm_main_udisks_cb_dev_del(void * data EINA_UNUSED,const Eldbus_Message * msg)226 _e_fm_main_udisks_cb_dev_del(void *data EINA_UNUSED, const Eldbus_Message *msg)
227 {
228    char *path;
229    E_Volume *v;
230 
231    if (!eldbus_message_arguments_get(msg, "o", &path))
232      return;
233    DBG("DB DEV-: %s", path);
234    if ((v = _volume_find_by_dbus_path(path)))
235      {
236         if (v->optype == E_VOLUME_OP_TYPE_EJECT)
237           _e_fm_main_udisks_cb_vol_ejected(v);
238      }
239    _e_fm_main_udisks_volume_del(path);
240    _e_fm_main_udisks_storage_del(path);
241 }
242 
243 static void
_e_fm_main_udisks_cb_prop_modified(void * data,const Eldbus_Message * msg EINA_UNUSED)244 _e_fm_main_udisks_cb_prop_modified(void *data,
245                                    const Eldbus_Message *msg EINA_UNUSED)
246 {
247    E_Volume *v = data;
248    eldbus_proxy_property_get_all(v->proxy, _e_fm_main_udisks_cb_vol_prop, v);
249 }
250 
251 static Eina_Bool
_storage_del(void * data)252 _storage_del(void *data)
253 {
254    const char *path = data;
255    _e_fm_main_udisks_storage_del(path);
256    return ECORE_CALLBACK_CANCEL;
257 }
258 
259 static void
_e_fm_main_udisks_cb_store_prop(void * data,const Eldbus_Message * msg,Eldbus_Pending * pending EINA_UNUSED)260 _e_fm_main_udisks_cb_store_prop(void *data, const Eldbus_Message *msg,
261                                 Eldbus_Pending *pending EINA_UNUSED)
262 {
263    E_Storage *s = data;
264    const char *name, *txt;
265    Eldbus_Message_Iter *dict, *entry;
266 
267    if (eldbus_message_error_get(msg, &name, &txt))
268      {
269         ERR("Error %s %s.", name, txt);
270         return;
271      }
272    if (!eldbus_message_arguments_get(msg, "a{sv}", &dict))
273      {
274         ERR("Error getting arguments.");
275         return;
276      }
277 
278    while (eldbus_message_iter_get_and_next(dict, 'e', &entry))
279      {
280         char *key;
281         Eldbus_Message_Iter *var;
282 
283         if (!eldbus_message_iter_arguments_get(entry, "sv", &key, &var))
284           continue;
285         if (!strcmp(key, "DeviceFile"))
286           {
287              const char *udi;
288              if (eldbus_message_iter_arguments_get(var, "s", &udi))
289                eina_stringshare_replace(&s->udi, udi);
290           }
291         else if (!strcmp(key, "DriveConnectionInterface"))
292           {
293              const char *bus;
294              if (eldbus_message_iter_arguments_get(var, "s", &bus))
295                {
296                   if (s->bus)
297                     eina_stringshare_del(bus);
298                   s->bus = eina_stringshare_add(bus);
299                }
300           }
301         else if (!strcmp(key, "DriveMediaCompatibility"))
302           {
303              Eldbus_Message_Iter *inner_array;
304              const char *media;
305 
306              if (!eldbus_message_iter_arguments_get(var, "as", &inner_array))
307                continue;
308 
309              while(eldbus_message_iter_get_and_next(inner_array, 's', &media))
310                {
311                   eina_stringshare_replace(&s->drive_type, media);
312                   break;
313                }
314           }
315         else if (!strcmp(key, "DriveModel"))
316           {
317              const char *model;
318              if (eldbus_message_iter_arguments_get(var, "s", &model))
319                eina_stringshare_replace(&s->model, model);
320           }
321         else if (!strcmp(key, "DriveVendor"))
322            {
323               const char *vendor;
324               if (eldbus_message_iter_arguments_get(var, "s", &vendor))
325                 {
326                    if (s->vendor)
327                      eina_stringshare_del(s->vendor);
328                    s->vendor = eina_stringshare_add(vendor);
329                 }
330            }
331         else if (!strcmp(key, "DriveSerial"))
332            {
333               const char *serial;
334               if (eldbus_message_iter_arguments_get(var, "s", &serial))
335                 {
336                    if (s->serial)
337                      eina_stringshare_del(s->serial);
338                    s->serial = eina_stringshare_add(serial);
339                 }
340            }
341         else if (!strcmp(key, "DeviceIsSystemInternal"))
342           eldbus_message_iter_arguments_get(var, "b", &s->system_internal);
343         else if (!strcmp(key, "DeviceIsMediaAvailable"))
344           eldbus_message_iter_arguments_get(var, "b", &s->media_available);
345         else if (!strcmp(key, "DeviceSize"))
346           eldbus_message_iter_arguments_get(var, "t", &s->media_size);
347         else if (!strcmp(key, "DriveIsMediaEjectable"))
348           eldbus_message_iter_arguments_get(var, "b", &s->requires_eject);
349         else if (!strcmp(key, "DriveCanDetach"))
350           eldbus_message_iter_arguments_get(var, "b", &s->hotpluggable);
351         else if (!strcmp(key, "DeviceIsMediaChangeDetectionInhibited"))
352           eldbus_message_iter_arguments_get(var, "b", &s->media_check_enabled);
353         else if (!strcmp(key, "DevicePresentationIconName"))
354           {
355              const char *icon;
356              if (eldbus_message_iter_arguments_get(var, "s", &icon))
357                {
358                   if (s->icon.drive)
359                     eina_stringshare_del(s->icon.drive);
360                   s->icon.drive = NULL;
361                   if (icon[0])
362                     s->icon.drive = eina_stringshare_add(icon);
363                   s->icon.volume = s->icon.drive;
364                }
365           }
366      }
367    if (!s->udi)
368      {
369         ERR("removing storage with null udi %s", s->dbus_path);
370         ecore_idler_add(_storage_del, s->dbus_path);
371         return;
372      }
373    if (s->system_internal)
374      {
375         DBG("removing storage internal %s", s->udi);
376         ecore_idler_add(_storage_del, s->udi);
377         return;
378      }
379    /* force it to be removable if it passed the above tests */
380    s->removable = EINA_TRUE;
381    INF("++STO:\n  udi: %s\n  bus: %s\n  drive_type: %s\n  model: %s\n  vendor: %s\n  serial: %s\n  icon.drive: %s\n  icon.volume: %s\n", s->udi, s->bus, s->drive_type, s->model, s->vendor, s->serial, s->icon.drive, s->icon.volume);
382    s->validated = EINA_TRUE;
383    {
384       void *msg_data;
385       int msg_size;
386 
387       msg_data = _e_fm_shared_codec_storage_encode(s, &msg_size);
388       if (msg_data)
389         {
390            ecore_ipc_server_send(_e_fm_ipc_server,
391                                  6 /*E_IPC_DOMAIN_FM*/,
392                                  E_FM_OP_STORAGE_ADD,
393                                  0, 0, 0, msg_data, msg_size);
394            free(msg_data);
395         }
396    }
397    return;
398 }
399 
400 static Eina_Bool
_idler_volume_del(void * data)401 _idler_volume_del(void *data)
402 {
403    const char *path = data;
404    _e_fm_main_udisks_volume_del(path);
405    return ECORE_CALLBACK_CANCEL;
406 }
407 
408 static void
_e_fm_main_udisks_cb_vol_prop(void * data,const Eldbus_Message * msg,Eldbus_Pending * pending EINA_UNUSED)409 _e_fm_main_udisks_cb_vol_prop(void *data, const Eldbus_Message *msg,
410                               Eldbus_Pending *pending EINA_UNUSED)
411 {
412    E_Volume *v = data;
413    E_Storage *s = NULL;
414    const char *txt, *message;
415    Eldbus_Message_Iter *array, *dict;
416 
417    DBG("volume=%s",v->dbus_path);
418 
419    if (eldbus_message_error_get(msg, &txt, &message))
420      {
421         ERR("Error: %s %s\nVolume: %s", txt, message, v->udi);
422         return;
423      }
424 
425    if (!eldbus_message_arguments_get(msg, "a{sv}", &array))
426      {
427         ERR("Error getting values.");
428         return;
429      }
430 
431    while (eldbus_message_iter_get_and_next(array, 'e', &dict))
432      {
433         Eldbus_Message_Iter *var;
434         const char *key;
435 
436         if (!eldbus_message_iter_arguments_get(dict, "sv", &key, &var))
437           continue;
438         if (!strcmp(key, "DeviceFile"))
439           {
440              const char *udi;
441              if (!eldbus_message_iter_arguments_get(var, "s", &udi))
442                continue;
443              if (udi && v->first_time)
444                eina_stringshare_replace(&v->udi, udi);
445           }
446         else if (!strcmp(key, "DeviceIsSystemInternal"))
447           {
448              Eina_Bool internal;
449              eldbus_message_iter_arguments_get(var, "b", &internal);
450              if (internal)
451                {
452                   DBG("removing is internal %s", v->dbus_path);
453                   ecore_idler_add(_idler_volume_del, v->dbus_path);
454                   return;
455                }
456           }
457         else if (!strcmp(key, "DevicePresentationHide"))
458           {
459              Eina_Bool hid;
460              eldbus_message_iter_arguments_get(var, "b", &hid);
461              if (hid)
462                {
463                   DBG("removing is hidden %s", v->dbus_path);
464                   ecore_idler_add(_idler_volume_del, v->dbus_path);
465                   return;
466                }
467           }
468         else if (!strcmp(key, "DeviceIsMediaChangeDetectionInhibited"))
469           {
470              Eina_Bool inibited;
471              eldbus_message_iter_arguments_get(var, "b", &inibited);
472              if (inibited)
473                {
474                   /* skip volumes with volume.ignore set */
475                   DBG("removing is inibited %s", v->dbus_path);
476                   ecore_idler_add(_idler_volume_del, v->dbus_path);
477                   return;
478                }
479           }
480         else if (!strcmp(key, "DeviceIsLuks"))
481           eldbus_message_iter_arguments_get(var, "b", &v->encrypted);
482         else if (!strcmp(key, "IdUuid"))
483           {
484              const char *uuid;
485              if (!eldbus_message_iter_arguments_get(var, "s", &uuid))
486                continue;
487              eina_stringshare_replace(&v->uuid, uuid);
488           }
489         else if (!strcmp(key, "IdLabel"))
490           {
491              const char *label;
492              if (!eldbus_message_iter_arguments_get(var, "s", &label))
493                continue;
494              eina_stringshare_replace(&v->label, label);
495           }
496         else if (!strcmp(key, "DeviceMountPaths"))
497           {
498              Eldbus_Message_Iter *inner_array;
499              const char *path;
500 
501              if (!eldbus_message_iter_arguments_get(var, "as", &inner_array))
502                continue;
503 
504              while (eldbus_message_iter_get_and_next(inner_array, 's', &path))
505                {
506                   eina_stringshare_replace(&v->mount_point, path);
507                   break;
508                }
509           }
510         else if (!strcmp(key, "IdType"))
511           {
512              const char *type;
513              if (!eldbus_message_iter_arguments_get(var, "s", &type))
514                continue;
515              eina_stringshare_replace(&v->fstype, type);
516           }
517         else if (!strcmp(key, "DeviceSize"))
518           eldbus_message_iter_arguments_get(var, "t", &v->size);
519         else if (!strcmp(key, "DeviceIsMounted"))
520           eldbus_message_iter_arguments_get(var, "b", &v->mounted);
521         else if (!strcmp(key, "DeviceIsLuksCleartext"))
522           eldbus_message_iter_arguments_get(var, "b", &v->unlocked);
523         else if (!strcmp(key, "DeviceIsPartition"))
524           eldbus_message_iter_arguments_get(var, "b", &v->partition);
525         else if (!strcmp(key, "PartitionNumber"))
526           eldbus_message_iter_arguments_get(var, "i", &v->partition_number);
527         else if (!strcmp(key, "PartitionLabel"))
528           {
529              const char *partition_label;
530              if (!eldbus_message_iter_arguments_get(var, "s", &partition_label))
531                continue;
532              eina_stringshare_replace(&v->partition_label, partition_label);
533           }
534         else if (!strcmp(key, "LuksCleartextSlave"))
535           {
536              const char *enc;
537              E_Volume *venc;
538              if (!eldbus_message_iter_arguments_get(var, "o", &enc))
539                continue;
540              eina_stringshare_replace(&v->partition_label, enc);
541              venc = _e_fm_main_udisks_volume_find(enc);
542              if (!venc)
543                continue;
544              eina_stringshare_replace(&v->parent, venc->parent);
545              v->storage = venc->storage;
546              v->storage->volumes = eina_list_append(v->storage->volumes, v);
547           }
548         else if (!strcmp(key, "PartitionSlave"))
549           {
550              char *partition_slave, buf[4096];
551              if (!eldbus_message_iter_arguments_get(var, "o", &partition_slave))
552                continue;
553              if ((!partition_slave) || (strlen(partition_slave) < sizeof("/org/freedesktop/UDisks/devices/")))
554                eina_stringshare_replace(&v->parent, partition_slave);
555              else
556                {
557                   snprintf(buf, sizeof(buf), "/dev/%s", partition_slave + sizeof("/org/freedesktop/UDisks/devices/") - 1);
558                   eina_stringshare_replace(&v->parent, buf);
559                }
560           }
561 
562      }
563    if (!v->udi)
564      {
565         ERR("!udi %s", v->dbus_path);
566         ecore_idler_add(_idler_volume_del, v);
567         return;
568      }
569    if (!v->label) eina_stringshare_replace(&v->label, v->uuid);
570    if (v->parent && v->partition)
571      {
572         s = e_storage_find(v->parent);
573         if (s)
574           {
575              v->storage = s;
576              if (!eina_list_data_find_list(s->volumes, v))
577                s->volumes = eina_list_append(s->volumes, v);
578           }
579      }
580    else
581      {
582         eina_stringshare_replace(&v->parent, v->udi);
583         s = e_storage_find(v->udi);
584         if (s)
585           {
586              v->storage = s;
587              if (!eina_list_data_find_list(s->volumes, v))
588                s->volumes = eina_list_append(s->volumes, v);
589           }
590         else
591           {
592              v->storage = _e_fm_main_udisks_storage_add(
593                                            eina_stringshare_add(v->dbus_path));
594              /* disk is both storage and volume */
595              if (v->storage)
596                v->storage->volumes = eina_list_append(v->storage->volumes, v);
597           }
598      }
599 
600    switch (v->optype)
601      {
602       case E_VOLUME_OP_TYPE_MOUNT:
603         _e_fm_main_udisks_cb_vol_mounted(v);
604         return;
605       case E_VOLUME_OP_TYPE_UNMOUNT:
606         _e_fm_main_udisks_cb_vol_unmounted(v);
607         return;
608       case E_VOLUME_OP_TYPE_EJECT:
609         _e_fm_main_udisks_cb_vol_unmounted_before_eject(v);
610         return;
611       default:
612         break;
613      }
614 
615 //   printf("++VOL:\n  udi: %s\n  uuid: %s\n  fstype: %s\n  size: %llu\n label: %s\n  partition: %d\n  partition_number: %d\n partition_label: %s\n  mounted: %d\n  mount_point: %s", v->udi, v->uuid, v->fstype, v->size, v->label, v->partition, v->partition_number, v->partition ? v->partition_label : "(not a partition)", v->mounted, v->mount_point);
616 //   if (s) printf("  for storage: %s", s->udi);
617 //   else printf("  storage unknown");
618    v->validated = EINA_TRUE;
619    e_fm_ipc_volume_add(v);
620    return;
621 }
622 
623 static int
_e_fm_main_udisks_format_error_msg(char ** buf,E_Volume * v,const char * name,const char * message)624 _e_fm_main_udisks_format_error_msg(char     **buf,
625                                    E_Volume  *v,
626                                    const char *name,
627                                    const char *message)
628 {
629    int size, vu, vm = 1, en;
630    char *tmp;
631 
632    vu = strlen(v->udi) + 1;
633    if (v->mount_point) vm = strlen(v->mount_point) + 1;
634    en = strlen(name) + 1;
635    size = vu + vm + en + strlen(message) + 1;
636    tmp = *buf = malloc(size);
637 
638    strcpy(tmp, v->udi);
639    tmp += vu;
640    if (v->mount_point)
641      {
642         strcpy(tmp, v->mount_point);
643         tmp += vm;
644      }
645    else
646      {
647         *tmp = 0;
648         tmp += vm;
649      }
650    strcpy(tmp, name);
651    tmp += en;
652    strcpy(tmp, message);
653 
654    return size;
655 }
656 
657 static Eina_Bool
_e_fm_main_udisks_vol_mount_timeout(E_Volume * v)658 _e_fm_main_udisks_vol_mount_timeout(E_Volume *v)
659 {
660    char *buf;
661    int size;
662 
663    v->guard = NULL;
664 
665    if (v->op)
666      eldbus_pending_cancel(v->op);
667    v->op = NULL;
668    v->optype = E_VOLUME_OP_TYPE_NONE;
669    size = _e_fm_main_udisks_format_error_msg(&buf, v,
670                        "org.enlightenment.fm2.MountTimeout",
671                        "Unable to mount the volume with specified time-out.");
672    ecore_ipc_server_send(_e_fm_ipc_server, 6 /*E_IPC_DOMAIN_FM*/, E_FM_OP_MOUNT_ERROR,
673                          0, 0, 0, buf, size);
674    free(buf);
675 
676    return ECORE_CALLBACK_CANCEL;
677 }
678 
679 static void
_e_fm_main_udisks_cb_vol_mounted(E_Volume * v)680 _e_fm_main_udisks_cb_vol_mounted(E_Volume *v)
681 {
682    char *buf;
683    int size;
684 
685    if (v->guard)
686      {
687         ecore_timer_del(v->guard);
688         v->guard = NULL;
689      }
690 
691    if (!v->mount_point) return; /* come back later */
692 
693    v->optype = E_VOLUME_OP_TYPE_NONE;
694    v->op = NULL;
695    v->mounted = EINA_TRUE;
696    INF("MOUNT: %s from %s", v->udi, v->mount_point);
697    size = strlen(v->udi) + 1 + strlen(v->mount_point) + 1;
698    buf = alloca(size);
699    strcpy(buf, v->udi);
700    strcpy(buf + strlen(buf) + 1, v->mount_point);
701    ecore_ipc_server_send(_e_fm_ipc_server,
702                          6 /*E_IPC_DOMAIN_FM*/,
703                          E_FM_OP_MOUNT_DONE,
704                          0, 0, 0, buf, size);
705 }
706 
707 static Eina_Bool
_e_fm_main_udisks_vol_unmount_timeout(E_Volume * v)708 _e_fm_main_udisks_vol_unmount_timeout(E_Volume *v)
709 {
710    char *buf;
711    int size;
712 
713    v->guard = NULL;
714    if (v->op)
715      eldbus_pending_cancel(v->op);
716    v->op = NULL;
717    v->optype = E_VOLUME_OP_TYPE_NONE;
718    size = _e_fm_main_udisks_format_error_msg(&buf, v,
719                       "org.enlightenment.fm2.UnmountTimeout",
720                       "Unable to unmount the volume with specified time-out.");
721    ecore_ipc_server_send(_e_fm_ipc_server, 6 /*E_IPC_DOMAIN_FM*/, E_FM_OP_UNMOUNT_ERROR,
722                          0, 0, 0, buf, size);
723    free(buf);
724 
725    return ECORE_CALLBACK_CANCEL;
726 }
727 
728 static void
_e_fm_main_udisks_cb_vol_unmounted(E_Volume * v)729 _e_fm_main_udisks_cb_vol_unmounted(E_Volume *v)
730 {
731    char *buf;
732    int size;
733 
734    if (v->guard)
735      {
736         ecore_timer_del(v->guard);
737         v->guard = NULL;
738      }
739 
740    if (v->optype != E_VOLUME_OP_TYPE_EJECT)
741      {
742         v->optype = E_VOLUME_OP_TYPE_NONE;
743         v->op = NULL;
744      }
745 
746    v->mounted = EINA_FALSE;
747    INF("UNMOUNT: %s from %s", v->udi, v->mount_point);
748    size = strlen(v->udi) + 1 + strlen(v->mount_point) + 1;
749    buf = alloca(size);
750    strcpy(buf, v->udi);
751    strcpy(buf + strlen(buf) + 1, v->mount_point);
752    ecore_ipc_server_send(_e_fm_ipc_server,
753                          6 /*E_IPC_DOMAIN_FM*/,
754                          E_FM_OP_UNMOUNT_DONE,
755                          0, 0, 0, buf, size);
756 }
757 
758 static Eina_Bool
_e_fm_main_udisks_vol_eject_timeout(E_Volume * v)759 _e_fm_main_udisks_vol_eject_timeout(E_Volume *v)
760 {
761    char *buf;
762    int size;
763 
764    v->guard = NULL;
765    if (v->op)
766      eldbus_pending_cancel(v->op);
767    v->op = NULL;
768    v->optype = E_VOLUME_OP_TYPE_NONE;
769    size = _e_fm_main_udisks_format_error_msg(&buf, v,
770                          "org.enlightenment.fm2.EjectTimeout",
771                          "Unable to eject the media with specified time-out.");
772    ecore_ipc_server_send(_e_fm_ipc_server, 6 /*E_IPC_DOMAIN_FM*/, E_FM_OP_EJECT_ERROR,
773                          0, 0, 0, buf, size);
774    free(buf);
775 
776    return ECORE_CALLBACK_CANCEL;
777 }
778 
779 static void
_volume_task_cb(void * data EINA_UNUSED,const Eldbus_Message * msg EINA_UNUSED,Eldbus_Pending * pending EINA_UNUSED)780 _volume_task_cb(void *data EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED,
781                 Eldbus_Pending *pending EINA_UNUSED)
782 {
783    /**
784     * if eldbus_proxy_send has callback == NULL it will return a NULL
785     * but we need a Eldbus_Pending to be able to cancel it when timeout occurs
786     */
787    /* FIXME: this should not matter. If we don't have a callback, there's no
788     * reason to cancel it... cancelling has no effect other than saying eldbus we
789     * are not interested in the return anymore. I.e.: don't bother to  cancel it
790     */
791 }
792 
793 static Eldbus_Pending *
_volume_umount(Eldbus_Proxy * proxy)794 _volume_umount(Eldbus_Proxy *proxy)
795 {
796    Eldbus_Message *msg;
797    Eldbus_Message_Iter *array, *main_iter;
798 
799    msg = eldbus_proxy_method_call_new(proxy, "FilesystemUnmount");
800    main_iter = eldbus_message_iter_get(msg);
801    eldbus_message_iter_arguments_append(main_iter, "as", &array);
802    eldbus_message_iter_container_close(main_iter, array);
803 
804    return eldbus_proxy_send(proxy, msg, _volume_task_cb, NULL, -1);
805 }
806 
807 static Eldbus_Pending *
_volume_eject(Eldbus_Proxy * proxy)808 _volume_eject(Eldbus_Proxy *proxy)
809 {
810    Eldbus_Message *msg;
811    Eldbus_Message_Iter *array, *main_iter;
812 
813    msg = eldbus_proxy_method_call_new(proxy, "DriveEject");
814    main_iter = eldbus_message_iter_get(msg);
815    eldbus_message_iter_arguments_append(main_iter, "as", &array);
816    eldbus_message_iter_container_close(main_iter, array);
817 
818    return eldbus_proxy_send(proxy, msg, _volume_task_cb, NULL, -1);
819 }
820 
821 static Eldbus_Pending *
_volume_mount(Eldbus_Proxy * proxy,const char * fstype,Eina_List * opt)822 _volume_mount(Eldbus_Proxy *proxy, const char *fstype, Eina_List *opt)
823 {
824    Eldbus_Message *msg;
825    Eldbus_Message_Iter *array, *main_iter;
826    Eina_List *l;
827    const char *opt_txt;
828 
829    msg = eldbus_proxy_method_call_new(proxy, "FilesystemMount");
830    main_iter = eldbus_message_iter_get(msg);
831    eldbus_message_iter_arguments_append(main_iter, "sas", fstype, &array);
832    EINA_LIST_FOREACH(opt, l, opt_txt)
833      eldbus_message_iter_basic_append(array, 's', opt_txt);
834    eldbus_message_iter_container_close(main_iter, array);
835 
836    return eldbus_proxy_send(proxy, msg, _volume_task_cb, NULL, -1);
837 }
838 
839 static Eina_Bool
_e_fm_main_udisks_cb_vol_ejecting_after_unmount(E_Volume * v)840 _e_fm_main_udisks_cb_vol_ejecting_after_unmount(E_Volume *v)
841 {
842    v->guard = ecore_timer_loop_add(E_FM_EJECT_TIMEOUT, (Ecore_Task_Cb)_e_fm_main_udisks_vol_eject_timeout, v);
843    v->op = _volume_eject(v->storage->proxy);
844 
845    return ECORE_CALLBACK_CANCEL;
846 }
847 
848 static void
_e_fm_main_udisks_cb_vol_unmounted_before_eject(E_Volume * v)849 _e_fm_main_udisks_cb_vol_unmounted_before_eject(E_Volume      *v)
850 {
851    _e_fm_main_udisks_cb_vol_unmounted(v);
852 
853    // delay is required for all message handlers were executed after unmount
854    ecore_timer_loop_add(1.0, (Ecore_Task_Cb)_e_fm_main_udisks_cb_vol_ejecting_after_unmount, v);
855 }
856 
857 static void
_e_fm_main_udisks_cb_vol_ejected(E_Volume * v)858 _e_fm_main_udisks_cb_vol_ejected(E_Volume *v)
859 {
860    char *buf;
861    int size;
862 
863    if (v->guard)
864      {
865         ecore_timer_del(v->guard);
866         v->guard = NULL;
867      }
868 
869    v->optype = E_VOLUME_OP_TYPE_NONE;
870 
871    size = strlen(v->udi) + 1;
872    buf = alloca(size);
873    strcpy(buf, v->udi);
874    ecore_ipc_server_send(_e_fm_ipc_server,
875                          6 /*E_IPC_DOMAIN_FM*/,
876                          E_FM_OP_EJECT_DONE,
877                          0, 0, 0, buf, size);
878 }
879 
880 E_Volume *
_e_fm_main_udisks_volume_add(const char * path,Eina_Bool first_time)881 _e_fm_main_udisks_volume_add(const char *path,
882                              Eina_Bool   first_time)
883 {
884    E_Volume *v;
885    Eldbus_Object *obj;
886 
887    if (!path) return NULL;
888    if (_volume_find_by_dbus_path(path)) return NULL;
889    v = calloc(1, sizeof(E_Volume));
890    if (!v) return NULL;
891    v->dbus_path = path;
892    INF("VOL+ %s", path);
893    v->efm_mode = EFM_MODE_USING_UDISKS_MOUNT;
894    v->icon = NULL;
895    v->first_time = first_time;
896    _e_vols = eina_list_append(_e_vols, v);
897    obj = eldbus_object_get(_e_fm_main_udisks_conn, UDISKS_BUS, path);
898    v->proxy = eldbus_proxy_get(obj, UDISKS_DEVICE_INTERFACE);
899    eldbus_proxy_property_get_all(v->proxy, _e_fm_main_udisks_cb_vol_prop, v);
900    eldbus_proxy_signal_handler_add(v->proxy, "Changed",
901                                   _e_fm_main_udisks_cb_prop_modified, v);
902    v->guard = NULL;
903 
904    return v;
905 }
906 
907 void
_e_fm_main_udisks_volume_del(const char * path)908 _e_fm_main_udisks_volume_del(const char *path)
909 {
910    E_Volume *v;
911 
912    v = _volume_find_by_dbus_path(path);
913    if (!v) return;
914    _volume_del(v);
915 }
916 
917 static void
_volume_del(E_Volume * v)918 _volume_del(E_Volume *v)
919 {
920    if (v->guard)
921      {
922         ecore_timer_del(v->guard);
923         v->guard = NULL;
924      }
925    if (v->validated)
926      {
927         INF("--VOL %s", v->udi);
928         /* FIXME: send event of storage volume (disk) removed */
929            ecore_ipc_server_send(_e_fm_ipc_server,
930                                  6 /*E_IPC_DOMAIN_FM*/,
931                                  E_FM_OP_VOLUME_DEL,
932                                  0, 0, 0, v->udi, eina_stringshare_strlen(v->udi) + 1);
933      }
934    v->optype = E_VOLUME_OP_TYPE_NONE;
935    if (v->storage && v->storage->requires_eject) return; /* udisks is stupid about ejectable media, so we have to keep stuff
936                                    * around for all eternity instead of deleting it constantly. oh noes.
937                                    */
938    if (v->proxy)
939      {
940         Eldbus_Object *obj = eldbus_proxy_object_get(v->proxy);
941         eldbus_proxy_unref(v->proxy);
942         eldbus_object_unref(obj);
943      }
944    _e_vols = eina_list_remove(_e_vols, v);
945    _e_fm_shared_device_volume_free(v);
946 }
947 
948 E_Volume *
_e_fm_main_udisks_volume_find(const char * udi)949 _e_fm_main_udisks_volume_find(const char *udi)
950 {
951    Eina_List *l;
952    E_Volume *v;
953 
954    if (!udi) return NULL;
955    EINA_LIST_FOREACH(_e_vols, l, v)
956      {
957         if (!v->udi) continue;
958         if (!strcmp(udi, v->udi)) return v;
959      }
960    return NULL;
961 }
962 
963 static E_Volume *
_volume_find_by_dbus_path(const char * path)964 _volume_find_by_dbus_path(const char *path)
965 {
966    Eina_List *l;
967    E_Volume *v;
968 
969    if (!path) return NULL;
970    EINA_LIST_FOREACH(_e_vols, l, v)
971      if (!strcmp(path, v->dbus_path)) return v;
972    return NULL;
973 }
974 
975 void
_e_fm_main_udisks_volume_eject(E_Volume * v)976 _e_fm_main_udisks_volume_eject(E_Volume *v)
977 {
978    if (!v || v->guard) return;
979    if (v->mounted)
980      {
981         v->guard = ecore_timer_loop_add(E_FM_UNMOUNT_TIMEOUT, (Ecore_Task_Cb)_e_fm_main_udisks_vol_unmount_timeout, v);
982         v->op = _volume_umount(v->proxy);
983      }
984    else
985      {
986         v->guard = ecore_timer_loop_add(E_FM_EJECT_TIMEOUT, (Ecore_Task_Cb)_e_fm_main_udisks_vol_eject_timeout, v);
987         v->op = _volume_eject(v->storage->proxy);
988      }
989    v->optype = E_VOLUME_OP_TYPE_EJECT;
990 }
991 
992 void
_e_fm_main_udisks_volume_unmount(E_Volume * v)993 _e_fm_main_udisks_volume_unmount(E_Volume *v)
994 {
995    if (!v || v->guard) return;
996    INF("unmount %s %s", v->udi, v->mount_point);
997 
998    v->guard = ecore_timer_loop_add(E_FM_UNMOUNT_TIMEOUT, (Ecore_Task_Cb)_e_fm_main_udisks_vol_unmount_timeout, v);
999    v->op = _volume_umount(v->proxy);
1000    v->optype = E_VOLUME_OP_TYPE_UNMOUNT;
1001 }
1002 
1003 void
_e_fm_main_udisks_volume_mount(E_Volume * v)1004 _e_fm_main_udisks_volume_mount(E_Volume *v)
1005 {
1006    char buf[256];
1007    char buf2[256];
1008    Eina_List *opt = NULL;
1009 
1010    if ((!v) || (v->guard))
1011      return;
1012 
1013    INF("mount %s %s [fs type = %s]", v->udi, v->mount_point, v->fstype);
1014 
1015    // Map uid to current user if possible
1016    // Possible filesystems found in udisks source (src/udiskslinuxfilesystem.c) as of 2012-07-11
1017    if ((!strcmp(v->fstype, "vfat")) ||
1018        (!strcmp(v->fstype, "ntfs")) ||
1019        (!strcmp(v->fstype, "iso9660")) ||
1020        (!strcmp(v->fstype, "udf"))
1021        )
1022      {
1023         snprintf(buf, sizeof(buf), "uid=%i", (int)getuid());
1024         opt = eina_list_append(opt, buf);
1025      }
1026 
1027    // force utf8 as the encoding - e only likes/handles utf8. its the
1028    // pseudo-standard these days anyway for "linux" for intl text to work
1029    // everywhere. problem is some fs's use differing options and udisks
1030    // doesn't allow some options with certain filesystems.
1031    // Valid options found in udisks (src/udiskslinuxfilesystem.c) as of 2012-07-11
1032    // Note that these options are default with the latest udisks, kept here to
1033    // avoid breakage in the future (hopefully).
1034    if (!strcmp(v->fstype, "vfat"))
1035      {
1036         snprintf(buf2, sizeof(buf2), "utf8=1");
1037         opt = eina_list_append(opt, buf2);
1038      }
1039    else if ((!strcmp(v->fstype, "iso9660")) ||
1040             (!strcmp(v->fstype, "udf"))
1041             )
1042      {
1043         snprintf(buf2, sizeof(buf2), "iocharset=utf8");
1044         opt = eina_list_append(opt, buf2);
1045      }
1046 
1047    v->guard = ecore_timer_loop_add(E_FM_MOUNT_TIMEOUT, (Ecore_Task_Cb)_e_fm_main_udisks_vol_mount_timeout, v);
1048 
1049    // It was previously noted here that ubuntu 10.04 failed to mount if opt was passed to
1050    // e_udisks_volume_mount.  The reason at the time was unknown and apparently never found.
1051    // I theorize that this was due to improper mount options being passed (namely the utf8 options).
1052    // If this still fails on Ubuntu 10.04 then an actual fix should be found.
1053    v->op = _volume_mount(v->proxy, v->fstype, opt);
1054 
1055    eina_list_free(opt);
1056    v->optype = E_VOLUME_OP_TYPE_MOUNT;
1057 }
1058 
1059 void
_e_fm_main_udisks_init(void)1060 _e_fm_main_udisks_init(void)
1061 {
1062    eldbus_init();
1063    _e_fm_main_udisks_conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM);
1064    if (!_e_fm_main_udisks_conn) return;
1065 
1066    eldbus_name_start(_e_fm_main_udisks_conn, UDISKS_BUS, 0,
1067                     _e_fm_main_udisks_name_start, NULL);
1068 }
1069 
1070 void
_e_fm_main_udisks_shutdown(void)1071 _e_fm_main_udisks_shutdown(void)
1072 {
1073    if (_e_fm_main_udisks_proxy)
1074      {
1075         Eldbus_Object *obj;
1076         obj = eldbus_proxy_object_get(_e_fm_main_udisks_proxy);
1077         eldbus_proxy_unref(_e_fm_main_udisks_proxy);
1078         eldbus_object_unref(obj);
1079      }
1080    if (_e_fm_main_udisks_conn)
1081      {
1082         eldbus_connection_unref(_e_fm_main_udisks_conn);
1083         eldbus_shutdown();
1084      }
1085 }
1086 
1087 E_Storage *
_e_fm_main_udisks_storage_add(const char * path)1088 _e_fm_main_udisks_storage_add(const char *path)
1089 {
1090    E_Storage *s;
1091    Eldbus_Object *obj;
1092 
1093    if (!path) return NULL;
1094    if (_storage_find_by_dbus_path(path)) return NULL;
1095    s = calloc(1, sizeof(E_Storage));
1096    if (!s) return NULL;
1097 
1098    DBG("STORAGE+=%s", path);
1099    s->dbus_path = path;
1100    _e_stores = eina_list_append(_e_stores, s);
1101    obj = eldbus_object_get(_e_fm_main_udisks_conn, UDISKS_BUS, path);
1102    s->proxy = eldbus_proxy_get(obj, UDISKS_DEVICE_INTERFACE);
1103    eldbus_proxy_property_get_all(s->proxy, _e_fm_main_udisks_cb_store_prop, s);
1104    return s;
1105 }
1106 
1107 void
_e_fm_main_udisks_storage_del(const char * path)1108 _e_fm_main_udisks_storage_del(const char *path)
1109 {
1110    E_Storage *s;
1111 
1112    s = _storage_find_by_dbus_path(path);
1113    if (!s) return;
1114    if (s->validated)
1115      {
1116         INF("--STO %s", s->udi);
1117           ecore_ipc_server_send(_e_fm_ipc_server,
1118                                 6 /*E_IPC_DOMAIN_FM*/,
1119                                 E_FM_OP_STORAGE_DEL,
1120                                 0, 0, 0, s->udi, strlen(s->udi) + 1);
1121      }
1122    _e_stores = eina_list_remove(_e_stores, s);
1123    if (s->proxy)
1124      {
1125         Eldbus_Object *obj = eldbus_proxy_object_get(s->proxy);
1126         eldbus_proxy_unref(s->proxy);
1127         eldbus_object_unref(obj);
1128      }
1129    _e_fm_shared_device_storage_free(s);
1130 }
1131 
1132 static E_Storage *
_storage_find_by_dbus_path(const char * path)1133 _storage_find_by_dbus_path(const char *path)
1134 {
1135    Eina_List *l;
1136    E_Storage *s;
1137 
1138    EINA_LIST_FOREACH(_e_stores, l, s)
1139      if (!strcmp(path, s->dbus_path)) return s;
1140    return NULL;
1141 }
1142 
1143 E_Storage *
_e_fm_main_udisks_storage_find(const char * udi)1144 _e_fm_main_udisks_storage_find(const char *udi)
1145 {
1146    Eina_List *l;
1147    E_Storage *s;
1148 
1149    EINA_LIST_FOREACH(_e_stores, l, s)
1150      {
1151         if (!s->udi) continue;
1152         if (!strcmp(udi, s->udi)) return s;
1153      }
1154    return NULL;
1155 }
1156