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