summaryrefslogtreecommitdiff
path: root/src/lib/eeze_disk_mount.c
diff options
context:
space:
mode:
authorraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>2012-08-30 09:54:57 +0000
committerraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>2012-08-30 09:54:57 +0000
commit75cedceb190d191366c6cdec95f938f497b48aa9 (patch)
tree777edb8860438f02c0ebb7c64c11a33bdcff10f6 /src/lib/eeze_disk_mount.c
downloadeeze-75cedceb190d191366c6cdec95f938f497b48aa9.tar.gz
eeze-75cedceb190d191366c6cdec95f938f497b48aa9.tar.bz2
eeze-75cedceb190d191366c6cdec95f938f497b48aa9.zip
EFL 1.7 svn doobies
git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/branches/eeze-1.7@75862 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33
Diffstat (limited to 'src/lib/eeze_disk_mount.c')
-rw-r--r--src/lib/eeze_disk_mount.c465
1 files changed, 465 insertions, 0 deletions
diff --git a/src/lib/eeze_disk_mount.c b/src/lib/eeze_disk_mount.c
new file mode 100644
index 0000000..24c0ae4
--- /dev/null
+++ b/src/lib/eeze_disk_mount.c
@@ -0,0 +1,465 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#include <Ecore.h>
+#include <Eeze.h>
+#include <Eeze_Disk.h>
+
+#include "eeze_udev_private.h"
+#include "eeze_disk_private.h"
+
+#define EEZE_MOUNT_DEFAULT_OPTS "noexec,nosuid,utf8"
+
+EAPI int EEZE_EVENT_DISK_MOUNT = 0;
+EAPI int EEZE_EVENT_DISK_UNMOUNT = 0;
+EAPI int EEZE_EVENT_DISK_EJECT = 0;
+EAPI int EEZE_EVENT_DISK_ERROR = 0;
+static Ecore_Event_Handler *_mount_handler = NULL;
+Eina_List *eeze_events = NULL;
+
+/*
+ *
+ * PRIVATE
+ *
+ */
+
+static void
+_eeze_disk_mount_error_free(void *data __UNUSED__, Eeze_Event_Disk_Error *de)
+{
+ if (!de)
+ return;
+
+ eina_stringshare_del(de->message);
+ free(de);
+}
+
+static void
+_eeze_disk_mount_error_handler(Eeze_Disk *disk, const char *error)
+{
+ Eeze_Event_Disk_Error *de;
+
+ ERR("%s", error);
+ if (!(de = calloc(1, sizeof(Eeze_Event_Disk_Error))))
+ return;
+
+ de->disk = disk;
+ de->message = eina_stringshare_add(error);
+ /* FIXME: placeholder since currently there are only mount-type errors */
+ ecore_event_add(EEZE_EVENT_DISK_ERROR, de, (Ecore_End_Cb)_eeze_disk_mount_error_free, NULL);
+}
+
+static Eina_Bool
+_eeze_disk_mount_result_handler(void *data __UNUSED__, int type __UNUSED__, Ecore_Exe_Event_Del *ev)
+{
+ Eeze_Disk *disk;
+ Eina_List *l;
+ Eeze_Event_Disk_Mount *e;
+
+ if ((!ev) || (!ev->exe))
+ return ECORE_CALLBACK_RENEW;
+ disk = ecore_exe_data_get(ev->exe);
+
+ if ((!disk) || (!eeze_events) || (!(l = eina_list_data_find_list(eeze_events, disk))))
+ return ECORE_CALLBACK_RENEW;
+
+ eeze_events = eina_list_remove_list(eeze_events, l);
+ if (!disk->mounter) /* killed */
+ {
+ disk->mount_status = EEZE_DISK_NULL;
+ return ECORE_CALLBACK_RENEW;
+ }
+ if (disk->mount_status == EEZE_DISK_MOUNTING)
+ {
+ disk->mounter = NULL;
+ if (!ev->exit_code)
+ {
+ disk->mounted = EINA_TRUE;
+ e = malloc(sizeof(Eeze_Event_Disk_Mount));
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e, ECORE_CALLBACK_RENEW);
+ e->disk = disk;
+ ecore_event_add(EEZE_EVENT_DISK_MOUNT, e, NULL, NULL);
+ }
+ else if (ev->exit_code & 2)
+ _eeze_disk_mount_error_handler(disk, "system error (out of memory, cannot fork, no more loop devices)");
+ else if (ev->exit_code & 4)
+ _eeze_disk_mount_error_handler(disk, "internal mount bug");
+ else if (ev->exit_code & 8)
+ _eeze_disk_mount_error_handler(disk, "user interrupt");
+ else if (ev->exit_code & 16)
+ _eeze_disk_mount_error_handler(disk, "problems writing or locking /etc/mtab");
+ else if (ev->exit_code & 32)
+ _eeze_disk_mount_error_handler(disk, "mount failure");
+ else if (ev->exit_code & 64)
+ _eeze_disk_mount_error_handler(disk, "some mount succeeded");
+ else
+ _eeze_disk_mount_error_handler(disk, "incorrect invocation or permissions");
+ }
+ else if (disk->mount_status == EEZE_DISK_UNMOUNTING)
+ switch (ev->exit_code)
+ {
+ case 0:
+ e = malloc(sizeof(Eeze_Event_Disk_Unmount));
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e, ECORE_CALLBACK_RENEW);
+ e->disk = disk;
+ disk->mounter = NULL;
+ disk->mounted = EINA_FALSE;
+ ecore_event_add(EEZE_EVENT_DISK_UNMOUNT, e, NULL, NULL);
+ break;
+
+ default:
+ if (disk->mount_fail_count++ < 3)
+ {
+ INF("Could not unmount disk, retrying");
+ disk->mounter = ecore_exe_run(eina_strbuf_string_get(disk->unmount_cmd), disk);
+ eeze_events = eina_list_append(eeze_events, disk);
+ }
+ else
+ {
+ disk->mount_fail_count = 0;
+ _eeze_disk_mount_error_handler(disk, "Maximimum number of mount-related failures reached");
+ }
+ return ECORE_CALLBACK_RENEW;
+ }
+ else
+ switch (ev->exit_code)
+ {
+ case 0:
+ e = malloc(sizeof(Eeze_Event_Disk_Eject));
+ EINA_SAFETY_ON_NULL_RETURN_VAL(e, ECORE_CALLBACK_RENEW);
+ e->disk = disk;
+ disk->mounter = NULL;
+ if (disk->mount_status & EEZE_DISK_UNMOUNTING)
+ {
+ disk->mount_status |= EEZE_DISK_UNMOUNTING;
+ disk->mounted = EINA_FALSE;
+ ecore_event_add(EEZE_EVENT_DISK_UNMOUNT, e, NULL, NULL);
+ eeze_disk_eject(disk);
+ }
+ else
+ ecore_event_add(EEZE_EVENT_DISK_EJECT, e, NULL, NULL);
+ break;
+
+ default:
+ if (disk->mount_fail_count++ < 3)
+ {
+ INF("Could not eject disk, retrying");
+ if (disk->mount_status & EEZE_DISK_UNMOUNTING)
+ disk->mounter = ecore_exe_run(eina_strbuf_string_get(disk->unmount_cmd), disk);
+ else
+ disk->mounter = ecore_exe_run(eina_strbuf_string_get(disk->eject_cmd), disk);
+ eeze_events = eina_list_append(eeze_events, disk);
+ }
+ else
+ {
+ disk->mount_fail_count = 0;
+ _eeze_disk_mount_error_handler(disk, "Maximimum number of mount-related failures reached");
+ }
+ return ECORE_CALLBACK_RENEW;
+ }
+ return ECORE_CALLBACK_RENEW;
+}
+
+/*
+ *
+ * INVISIBLE
+ *
+ */
+
+Eina_Bool
+eeze_mount_init(void)
+{
+ EEZE_EVENT_DISK_MOUNT = ecore_event_type_new();
+ EEZE_EVENT_DISK_UNMOUNT = ecore_event_type_new();
+ EEZE_EVENT_DISK_EJECT = ecore_event_type_new();
+ EEZE_EVENT_DISK_ERROR = ecore_event_type_new();
+ _mount_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
+ (Ecore_Event_Handler_Cb)_eeze_disk_mount_result_handler, NULL);
+ return eeze_libmount_init();
+}
+
+void
+eeze_mount_shutdown(void)
+{
+ eeze_libmount_shutdown();
+ ecore_event_handler_del(_mount_handler);
+ _mount_handler = NULL;
+}
+
+/*
+ *
+ * API
+ *
+ */
+
+EAPI Eina_Bool
+eeze_disk_mounted_get(Eeze_Disk *disk)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE);
+
+ return eeze_disk_libmount_mounted_get(disk);
+}
+
+EAPI Eina_Bool
+eeze_disk_mountopts_set(Eeze_Disk *disk, unsigned long opts)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE);
+ if (opts != disk->mount_opts)
+ disk->mount_cmd_changed = EINA_TRUE;
+ disk->mount_opts = opts;
+ if (opts & EEZE_DISK_MOUNTOPT_UID)
+ disk->uid = getuid();
+ return EINA_TRUE;
+}
+
+EAPI unsigned long
+eeze_disk_mountopts_get(Eeze_Disk *disk)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, 0);
+#ifndef OLD_LIBMOUNT
+ if (!disk->mount_opts)
+ disk->mount_opts = eeze_disk_libmount_opts_get(disk);
+#endif
+ return disk->mount_opts;
+}
+
+EAPI Eina_Bool
+eeze_disk_mount_wrapper_set(Eeze_Disk *disk, const char *wrapper)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE);
+ if (wrapper) EINA_SAFETY_ON_TRUE_RETURN_VAL(!*wrapper, EINA_FALSE);
+ else
+ {
+ eina_stringshare_del(disk->mount_wrapper);
+ disk->mount_wrapper = NULL;
+ return EINA_TRUE;
+ }
+ eina_stringshare_replace(&disk->mount_wrapper, wrapper);
+ return EINA_TRUE;
+}
+
+EAPI const char *
+eeze_disk_mount_wrapper_get(Eeze_Disk *disk)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL);
+ return disk->mount_wrapper;
+}
+
+EAPI Eina_Bool
+eeze_disk_mount(Eeze_Disk *disk)
+{
+ struct stat st;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE);
+
+ if ((!disk->mount_point) && eeze_disk_libmount_mounted_get(disk))
+ return EINA_FALSE;
+
+ if (!disk->mount_cmd)
+ disk->mount_cmd = eina_strbuf_new();
+
+ if (disk->mount_cmd_changed)
+ {
+ const char *dev, *str;
+ eina_strbuf_string_free(disk->mount_cmd);
+ dev = eeze_disk_uuid_get(disk);
+ if (dev) str = "UUID=";
+ else
+ {
+ dev = eeze_disk_devpath_get(disk);
+ str = NULL;
+ }
+
+ if (!disk->mount_point)
+ {
+ const char *mp;
+ /* here we attempt to guess the mount point using libmount */
+ mp = eeze_disk_libmount_mp_lookup_by_uuid(disk->cache.uuid);
+ if (!mp)
+ {
+ const char *devpath;
+
+ devpath = eeze_disk_devpath_get(disk);
+ if (devpath)
+ {
+ mp = eeze_disk_libmount_mp_lookup_by_devpath(devpath);
+ eina_stringshare_del(devpath);
+ }
+ }
+ if (!eeze_disk_mount_point_set(disk, mp))
+ /* sometimes we fail */
+ return EINA_FALSE;
+ }
+
+ if ((!disk->mount_point) || (!disk->mount_point[0])) return EINA_FALSE;
+ if (disk->mount_wrapper)
+ eina_strbuf_append_printf(disk->mount_cmd, "%s ", disk->mount_wrapper);
+ if (disk->mount_opts == EEZE_DISK_MOUNTOPT_DEFAULTS)
+ eina_strbuf_append_printf(disk->mount_cmd, EEZE_MOUNT_BIN" -o "EEZE_MOUNT_DEFAULT_OPTS" %s%s %s", str ?: "", dev, disk->mount_point);
+ else if (!disk->mount_opts)
+ eina_strbuf_append_printf(disk->mount_cmd, EEZE_MOUNT_BIN" %s%s %s", str ?: "", dev, disk->mount_point);
+ else
+ {
+ eina_strbuf_append(disk->mount_cmd, EEZE_MOUNT_BIN" -o ");
+ /* trailing commas are okay */
+ if (disk->mount_opts & EEZE_DISK_MOUNTOPT_LOOP)
+ eina_strbuf_append(disk->mount_cmd, "loop,");
+ if (disk->mount_opts & EEZE_DISK_MOUNTOPT_UTF8)
+ {
+ const char *fstype;
+ eina_strbuf_append(disk->mount_cmd, "utf8,");
+ fstype = eeze_disk_fstype_get(disk);
+ if (fstype && (!strcmp(fstype, "jfs")))
+ eina_strbuf_append(disk->mount_cmd, "iocharset=utf8,");
+ }
+ if (disk->mount_opts & EEZE_DISK_MOUNTOPT_NOEXEC)
+ eina_strbuf_append(disk->mount_cmd, "noexec,");
+ if (disk->mount_opts & EEZE_DISK_MOUNTOPT_NODEV)
+ eina_strbuf_append(disk->mount_cmd, "nodev,");
+ if (disk->mount_opts & EEZE_DISK_MOUNTOPT_NOSUID)
+ eina_strbuf_append(disk->mount_cmd, "nosuid,");
+ if (disk->mount_opts & EEZE_DISK_MOUNTOPT_REMOUNT)
+ eina_strbuf_append(disk->mount_cmd, "remount,");
+ if (disk->mount_opts & EEZE_DISK_MOUNTOPT_UID)
+ eina_strbuf_append_printf(disk->mount_cmd, "uid=%i,", (int)disk->uid);
+ eina_strbuf_append_printf(disk->mount_cmd, " %s%s %s", str ?: "", dev, disk->mount_point);
+ }
+ disk->mount_cmd_changed = EINA_FALSE;
+ }
+
+ if (stat(disk->mount_point, &st))
+ {
+ INF("Creating not-existing mount point directory '%s'", disk->mount_point);
+ if (mkdir(disk->mount_point, S_IROTH | S_IWOTH | S_IXOTH))
+ ERR("Could not create directory: %s; hopefully this is handled by your mounter!", strerror(errno));
+ }
+ else if (!S_ISDIR(st.st_mode))
+ {
+ ERR("%s is not a directory!", disk->mount_point);
+ return EINA_FALSE;
+ }
+ INF("Mounting: %s", eina_strbuf_string_get(disk->mount_cmd));
+ disk->mounter = ecore_exe_run(eina_strbuf_string_get(disk->mount_cmd), disk);
+ if (!disk->mounter)
+ return EINA_FALSE;
+ eeze_events = eina_list_append(eeze_events, disk);
+ disk->mount_status = EEZE_DISK_MOUNTING;
+
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+eeze_disk_unmount(Eeze_Disk *disk)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE);
+
+ if (!eeze_disk_libmount_mounted_get(disk))
+ return EINA_TRUE;
+
+ if (!disk->unmount_cmd)
+ disk->unmount_cmd = eina_strbuf_new();
+
+ if (disk->unmount_cmd_changed)
+ {
+ eina_strbuf_string_free(disk->unmount_cmd);
+ if (disk->mount_wrapper)
+ eina_strbuf_append_printf(disk->unmount_cmd, "%s ", disk->mount_wrapper);
+ eina_strbuf_append_printf(disk->unmount_cmd, EEZE_UNMOUNT_BIN" %s", eeze_disk_devpath_get(disk));
+ disk->unmount_cmd_changed = EINA_FALSE;
+ }
+
+ INF("Unmounting: %s", eina_strbuf_string_get(disk->unmount_cmd));
+ disk->mounter = ecore_exe_run(eina_strbuf_string_get(disk->unmount_cmd), disk);
+ if (!disk->mounter)
+ return EINA_FALSE;
+
+ eeze_events = eina_list_append(eeze_events, disk);
+ disk->mount_status = EEZE_DISK_UNMOUNTING;
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+eeze_disk_eject(Eeze_Disk *disk)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE);
+
+ if (!disk->eject_cmd)
+ {
+ disk->eject_cmd = eina_strbuf_new();
+ if (disk->mount_wrapper)
+ eina_strbuf_append_printf(disk->eject_cmd, "%s ", disk->mount_wrapper);
+ eina_strbuf_append_printf(disk->eject_cmd, EEZE_EJECT_BIN" %s", eeze_disk_devpath_get(disk));
+ }
+
+ INF("Ejecting: %s", eina_strbuf_string_get(disk->eject_cmd));
+ if (eeze_disk_libmount_mounted_get(disk))
+ {
+ Eina_Bool ret;
+
+ ret = eeze_disk_unmount(disk);
+ if (ret) disk->mount_status |= EEZE_DISK_EJECTING;
+ return ret;
+ }
+ disk->mounter = ecore_exe_run(eina_strbuf_string_get(disk->eject_cmd), disk);
+ if (!disk->mounter)
+ return EINA_FALSE;
+
+ eeze_events = eina_list_append(eeze_events, disk);
+ disk->mount_status = EEZE_DISK_EJECTING;
+ return EINA_TRUE;
+}
+
+EAPI void
+eeze_disk_cancel(Eeze_Disk *disk)
+{
+ EINA_SAFETY_ON_NULL_RETURN(disk);
+ if ((!disk->mount_status) || (!disk->mounter)) return;
+ disk->mount_status = EEZE_DISK_NULL;
+ ecore_exe_kill(disk->mounter);
+ disk->mounter = NULL;
+}
+
+EAPI const char *
+eeze_disk_mount_point_get(Eeze_Disk *disk)
+{
+ const char *mp;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL);
+
+ if (disk->mount_point)
+ return disk->mount_point;
+
+ mp = eeze_disk_libmount_mp_lookup_by_devpath(eeze_disk_devpath_get(disk));
+ if (mp)
+ {
+ disk->mount_point = eina_stringshare_add(mp);
+ return disk->mount_point;
+ }
+ mp = eeze_disk_libmount_mp_lookup_by_uuid(eeze_disk_uuid_get(disk));
+ if (mp)
+ {
+ disk->mount_point = eina_stringshare_add(mp);
+ return disk->mount_point;
+ }
+ mp = eeze_disk_libmount_mp_lookup_by_label(eeze_disk_label_get(disk));
+ if (mp)
+ {
+ disk->mount_point = eina_stringshare_add(mp);
+ return disk->mount_point;
+ }
+ return NULL;
+}
+
+EAPI Eina_Bool
+eeze_disk_mount_point_set(Eeze_Disk *disk, const char *mount_point)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE);
+
+ eina_stringshare_replace(&disk->mount_point, mount_point);
+ disk->mount_cmd_changed = EINA_TRUE;
+ disk->unmount_cmd_changed = EINA_TRUE;
+ return EINA_TRUE;
+}