summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRusty Lynch <rusty.lynch@intel.com>2012-07-05 16:38:26 -0700
committerRusty Lynch <rusty.lynch@intel.com>2012-07-05 16:38:26 -0700
commit1268b43ff6ff9d5eb403b180013b1d64778d2815 (patch)
tree46fc7c2989f8d757648d872c635e9e8a3140ff76 /src
downloadeeze-1268b43ff6ff9d5eb403b180013b1d64778d2815.tar.gz
eeze-1268b43ff6ff9d5eb403b180013b1d64778d2815.tar.bz2
eeze-1268b43ff6ff9d5eb403b180013b1d64778d2815.zip
Initial import of a snapshot of svn version 73381
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/bin/Makefile.am49
-rw-r--r--src/bin/eeze_disk_ls.c53
-rw-r--r--src/bin/eeze_mount.c130
-rw-r--r--src/bin/eeze_scanner.c475
-rw-r--r--src/bin/eeze_scanner.h32
-rw-r--r--src/bin/eeze_udev_test.c238
-rw-r--r--src/bin/eeze_umount.c113
-rw-r--r--src/lib/Eeze.h560
-rw-r--r--src/lib/Eeze_Disk.h566
-rw-r--r--src/lib/Eeze_Net.h62
-rw-r--r--src/lib/Makefile.am39
-rw-r--r--src/lib/eeze_disk.c476
-rw-r--r--src/lib/eeze_disk_libmount.c494
-rw-r--r--src/lib/eeze_disk_libmount_old.c401
-rw-r--r--src/lib/eeze_disk_mount.c460
-rw-r--r--src/lib/eeze_disk_private.h92
-rw-r--r--src/lib/eeze_disk_udev.c90
-rw-r--r--src/lib/eeze_main.c104
-rw-r--r--src/lib/eeze_net.c321
-rw-r--r--src/lib/eeze_net_private.h53
-rw-r--r--src/lib/eeze_udev_find.c384
-rw-r--r--src/lib/eeze_udev_private.c200
-rw-r--r--src/lib/eeze_udev_private.h46
-rw-r--r--src/lib/eeze_udev_syspath.c292
-rw-r--r--src/lib/eeze_udev_walk.c65
-rw-r--r--src/lib/eeze_udev_watch.c441
27 files changed, 6238 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..97baf85
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,2 @@
+MAINTAINERCLEANFILES = Makefile.in
+SUBDIRS = lib bin
diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am
new file mode 100644
index 0000000..abf27ae
--- /dev/null
+++ b/src/bin/Makefile.am
@@ -0,0 +1,49 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+EEZE_CFLAGS = \
+-I$(top_srcdir)/src/lib \
+@EEZE_CFLAGS@
+
+noinst_PROGRAMS = @EEZE_UDEV_TEST_PRG@
+EXTRA_PROGRAMS = eeze_udev_test eeze_mount eeze_umount eeze_disk_ls eeze_scanner
+
+if HAVE_EEZE_MOUNT
+ DISK_PROGS = @EEZE_MOUNT_PRG@ @EEZE_UMOUNT_PRG@ @EEZE_DISK_LS_PRG@
+ SCAN_PROGS = @EEZE_SCANNER_PRG@
+else
+ DISK_PROGS =
+ SCAN_PROGS =
+endif
+
+bin_PROGRAMS = $(DISK_PROGS)
+util_PROGRAMS = $(SCAN_PROGS)
+utildir = @libdir@/enlightenment/utils
+
+eeze_udev_test_SOURCES = eeze_udev_test.c
+eeze_udev_test_CPPFLAGS = -I$(top_srcdir)/src/lib @EEZE_CFLAGS@
+eeze_udev_test_LDADD = $(top_builddir)/src/lib/libeeze.la @EEZE_LIBS@
+
+if HAVE_EEZE_MOUNT
+ eeze_mount_SOURCES = eeze_mount.c
+ eeze_mount_CFLAGS = -I$(top_srcdir)/src/lib $(EEZE_CFLAGS) @LIBMOUNT_CFLAGS@ @ECORE_FILE_CFLAGS@
+ eeze_mount_LDADD = $(top_builddir)/src/lib/libeeze.la @LIBMOUNT_LIBS@ @ECORE_FILE_LIBS@ @EEZE_LIBS@
+
+ eeze_umount_SOURCES = eeze_umount.c
+ eeze_umount_CFLAGS = -I$(top_srcdir)/src/lib $(EEZE_CFLAGS) @LIBMOUNT_CFLAGS@ @ECORE_FILE_CFLAGS@
+ eeze_umount_LDADD = $(top_builddir)/src/lib/libeeze.la @LIBMOUNT_LIBS@ @ECORE_FILE_LIBS@ @EEZE_LIBS@
+
+ eeze_disk_ls_SOURCES = eeze_disk_ls.c
+ eeze_disk_ls_CFLAGS = -I$(top_srcdir)/src/lib $(EEZE_CFLAGS) @LIBMOUNT_CFLAGS@ @ECORE_FILE_CFLAGS@
+ eeze_disk_ls_LDADD = $(top_builddir)/src/lib/libeeze.la @LIBMOUNT_LIBS@ @ECORE_FILE_LIBS@ @EEZE_LIBS@
+
+ eeze_scanner_SOURCES = eeze_scanner.c
+ eeze_scanner_CFLAGS = -I$(top_srcdir)/src/lib $(EEZE_CFLAGS) @LIBMOUNT_CFLAGS@ @ECORE_FILE_CFLAGS@ @ECORE_CON_CFLAGS@ @EET_CFLAGS@
+ eeze_scanner_LDADD = $(top_builddir)/src/lib/libeeze.la @LIBMOUNT_LIBS@ @ECORE_FILE_LIBS@ @ECORE_CON_LIBS@ @EET_LIBS@ @EEZE_LIBS@
+ includesdir = $(includedir)/eeze-@VMAJ@
+ includes_HEADERS = eeze_scanner.h
+
+setuid_root_mode = a=rx,u+xs
+install-data-hook:
+ @chmod $(setuid_root_mode) $(DESTDIR)$(libdir)/enlightenment/utils/eeze_scanner$(EXEEXT) || true
+
+endif
diff --git a/src/bin/eeze_disk_ls.c b/src/bin/eeze_disk_ls.c
new file mode 100644
index 0000000..46c4006
--- /dev/null
+++ b/src/bin/eeze_disk_ls.c
@@ -0,0 +1,53 @@
+#include <stdio.h>
+#include <Ecore.h>
+#include <Eeze.h>
+#include <Eeze_Disk.h>
+
+/* simple app to print disks and their mount points */
+
+int
+main(void)
+{
+ Eina_List *disks;
+ const char *syspath;
+
+ eeze_init();
+ eeze_disk_function();
+
+ disks = eeze_udev_find_by_type(EEZE_UDEV_TYPE_DRIVE_MOUNTABLE, NULL);
+ printf("Found the following mountable disks:\n");
+ EINA_LIST_FREE(disks, syspath)
+ {
+ Eeze_Disk *disk;
+
+ disk = eeze_disk_new(syspath);
+ printf("\t%s - %s:%s\n", syspath, eeze_disk_devpath_get(disk), eeze_disk_mount_point_get(disk));
+ eeze_disk_free(disk);
+ eina_stringshare_del(syspath);
+ }
+
+ disks = eeze_udev_find_by_type(EEZE_UDEV_TYPE_DRIVE_REMOVABLE, NULL);
+ printf("Found the following removable drives:\n");
+ EINA_LIST_FREE(disks, syspath)
+ {
+ Eeze_Disk *disk;
+
+ disk = eeze_disk_new(syspath);
+ printf("\t%s - %s:%s\n", syspath, eeze_disk_devpath_get(disk), eeze_disk_mount_point_get(disk));
+ eeze_disk_free(disk);
+ eina_stringshare_del(syspath);
+ }
+
+ disks = eeze_udev_find_by_type(EEZE_UDEV_TYPE_DRIVE_INTERNAL, NULL);
+ printf("Found the following internal drives:\n");
+ EINA_LIST_FREE(disks, syspath)
+ {
+ Eeze_Disk *disk;
+
+ disk = eeze_disk_new(syspath);
+ printf("\t%s - %s\n", syspath, eeze_disk_devpath_get(disk));
+ eeze_disk_free(disk);
+ eina_stringshare_del(syspath);
+ }
+ return 0;
+}
diff --git a/src/bin/eeze_mount.c b/src/bin/eeze_mount.c
new file mode 100644
index 0000000..1f1c561
--- /dev/null
+++ b/src/bin/eeze_mount.c
@@ -0,0 +1,130 @@
+#include <Eeze.h>
+#include <Eeze_Disk.h>
+#include <Ecore.h>
+#include <Ecore_File.h>
+#include <Ecore_Getopt.h>
+#include <stdio.h>
+
+/** This app can be used as a "dumb" replacement for mount. Just don't try anything fancy yet! */
+static const Ecore_Getopt opts =
+{
+ "eeze_mount",
+ "eeze_mount /dev/sdb1 /media/disk",
+ "1.0",
+ "(C) 2010 Mike Blumenkrantz",
+ "LGPL",
+ "Mount a disk using either its /sys/ path or its /dev/ path\n\n",
+ 1,
+ {
+ ECORE_GETOPT_STORE_TRUE('v', "verbose", "Enable debug output"),
+ ECORE_GETOPT_VERSION('V', "version"),
+ ECORE_GETOPT_COPYRIGHT('R', "copyright"),
+ ECORE_GETOPT_LICENSE('L', "license"),
+ ECORE_GETOPT_HELP('h', "help"),
+ ECORE_GETOPT_SENTINEL
+ }
+};
+
+void
+_mount_cb(void *data, int type, Eeze_Event_Disk_Mount *e)
+{
+ (void)data;
+ (void)type;
+ printf("Success!\n");
+ eeze_disk_free(e->disk);
+ ecore_main_loop_quit();
+}
+
+void
+_error_cb(void *data, int type, Eeze_Event_Disk_Error *de)
+{
+ (void)data;
+ (void)type;
+ printf("Could not mount disk with /dev/ path: %s!\n", eeze_disk_devpath_get(de->disk));
+ eeze_disk_free(de->disk);
+ ecore_main_loop_quit();
+}
+
+int
+main(int argc, char *argv[])
+{
+ int args;
+ const char *dev, *mount_point = NULL;
+ Eina_Bool verbose = EINA_FALSE, exit_option = EINA_FALSE;
+ Eeze_Disk *disk;
+
+ Ecore_Getopt_Value values[] =
+ {
+ ECORE_GETOPT_VALUE_BOOL(verbose),
+ ECORE_GETOPT_VALUE_BOOL(exit_option),
+ ECORE_GETOPT_VALUE_BOOL(exit_option),
+ ECORE_GETOPT_VALUE_BOOL(exit_option),
+ ECORE_GETOPT_VALUE_BOOL(exit_option)
+ };
+
+ if (argc < 2)
+ {
+ printf("Insufficient args specified!\n");
+ ecore_getopt_help(stderr, &opts);
+ exit(1);
+ }
+
+ ecore_init();
+ eeze_init();
+ ecore_app_args_set(argc, (const char **)argv);
+ args = ecore_getopt_parse(&opts, values, argc, argv);
+
+ if (exit_option)
+ return 0;
+
+ if (args < 0)
+ {
+ printf("No args specified!\n");
+ ecore_getopt_help(stderr, &opts);
+ exit(1);
+ }
+ if (verbose) eina_log_domain_level_set("eeze_disk", EINA_LOG_LEVEL_DBG);
+ dev = argv[args];
+ if (args + 1 < argc)
+ mount_point = argv[args + 1];
+ if ((!strncmp(dev, "/sys/", 5)) || (!strncmp(dev, "/dev/", 5)))
+ disk = eeze_disk_new(dev);
+ else if ((args == argc - 1) && (ecore_file_is_dir(dev)))
+ disk = eeze_disk_new_from_mount(dev);
+ else
+ {
+ printf("[Device] must be either a /dev/ path or a /sys/ path!\n");
+ ecore_getopt_help(stderr, &opts);
+ exit(1);
+ }
+ if (eeze_disk_mounted_get(disk))
+ {
+ printf("[%s] is already mounted!", dev);
+ exit(1);
+ }
+ if (argc - args > 1)
+ {
+ eeze_disk_mount_point_set(disk, mount_point);
+ if (eina_str_has_extension(dev, "iso"))
+ {
+ int f;
+ f = eeze_disk_mountopts_get(disk);
+ eeze_disk_mountopts_set(disk, f | EEZE_DISK_MOUNTOPT_LOOP);
+ }
+ }
+ ecore_event_handler_add(EEZE_EVENT_DISK_MOUNT, (Ecore_Event_Handler_Cb)_mount_cb, NULL);
+ ecore_event_handler_add(EEZE_EVENT_DISK_ERROR, (Ecore_Event_Handler_Cb)_error_cb, NULL);
+ eeze_disk_mountopts_get(disk);
+ if (!eeze_disk_mount(disk))
+ {
+ const char *mp;
+
+ mp = eeze_disk_mount_point_get(disk);
+ if (!mp) fprintf(stderr, "No mount point passed!\n");
+ else fprintf(stderr, "Mount operation could not be started!\n");
+ exit(1);
+ }
+ ecore_main_loop_begin();
+
+ return 0;
+}
diff --git a/src/bin/eeze_scanner.c b/src/bin/eeze_scanner.c
new file mode 100644
index 0000000..8d711b5
--- /dev/null
+++ b/src/bin/eeze_scanner.c
@@ -0,0 +1,475 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <Eet.h>
+#include <Eeze.h>
+#include <Ecore_Con.h>
+#include <Eeze_Disk.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "eeze_scanner.h"
+
+#define DBG(...) EINA_LOG_DOM_DBG(es_log_dom, __VA_ARGS__)
+#define INF(...) EINA_LOG_DOM_INFO(es_log_dom, __VA_ARGS__)
+#define WRN(...) EINA_LOG_DOM_WARN(es_log_dom, __VA_ARGS__)
+#define ERR(...) EINA_LOG_DOM_ERR(es_log_dom, __VA_ARGS__)
+#define CRI(...) EINA_LOG_DOM_CRIT(es_log_dom, __VA_ARGS__)
+
+static int es_log_dom = -1;
+static Ecore_Con_Server *svr = NULL;
+static Eet_Data_Descriptor *es_edd = NULL;
+static Eina_Hash *clients = NULL;
+
+static Eina_List *storage_devices = NULL;
+static Eina_List *storage_cdrom = NULL;
+
+static Eina_List *volume_cdrom = NULL;
+static Eina_List *volume_devices = NULL;
+
+static void
+event_send(const char *device, Eeze_Scanner_Event_Type type, Eina_Bool volume)
+{
+ Eeze_Scanner_Event ev;
+ const Eina_List *l;
+ Ecore_Con_Client *cl;
+
+ ev.device = device;
+ ev.type = type;
+ ev.volume = volume;
+ EINA_LIST_FOREACH(ecore_con_server_clients_get(svr), l, cl)
+ {
+ Eet_Connection *ec;
+
+ ec = eina_hash_find(clients, cl);
+ if (!ec) continue;
+ INF("Serializing event...");
+ eet_connection_send(ec, es_edd, &ev, NULL);
+ }
+}
+
+static Eina_Bool
+event_write(const void *data, size_t size, Ecore_Con_Client *cl)
+{
+ INF("Event sent!");
+ ecore_con_client_send(cl, data, size);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+disk_mount(void *data __UNUSED__, int type __UNUSED__, Eeze_Disk *disk)
+{
+ Eina_List *l;
+ Eeze_Scanner_Device *d;
+ if (eeze_disk_type_get(disk) != EEZE_DISK_TYPE_CDROM) return ECORE_CALLBACK_RENEW;
+
+ EINA_LIST_FOREACH(storage_cdrom, l, d)
+ {
+ if (d->device == eeze_disk_syspath_get(disk))
+ {
+ d->mounted = !d->mounted;
+ break;
+ }
+ }
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void
+cl_setup(Ecore_Con_Client *cl __UNUSED__, Eet_Connection *ec)
+{
+ Eina_List *l;
+ Eeze_Scanner_Device *dev;
+ Eeze_Scanner_Event ev;
+ const char *sys;
+
+ INF("Sending initial events to new client");
+ EINA_LIST_FOREACH(storage_devices, l, sys)
+ {
+ ev.device = sys;
+ ev.type = EEZE_SCANNER_EVENT_TYPE_ADD;
+ ev.volume = EINA_FALSE;
+ eet_connection_send(ec, es_edd, &ev, NULL);
+ }
+ EINA_LIST_FOREACH(storage_cdrom, l, dev)
+ {
+ ev.device = dev->device;
+ ev.type = EEZE_SCANNER_EVENT_TYPE_ADD;
+ ev.volume = EINA_FALSE;
+ eet_connection_send(ec, es_edd, &ev, NULL);
+ }
+ EINA_LIST_FOREACH(volume_devices, l, sys)
+ {
+ ev.device = sys;
+ ev.type = EEZE_SCANNER_EVENT_TYPE_ADD;
+ ev.volume = EINA_TRUE;
+ eet_connection_send(ec, es_edd, &ev, NULL);
+ }
+ EINA_LIST_FOREACH(volume_cdrom, l, dev)
+ {
+ ev.device = dev->device;
+ ev.type = EEZE_SCANNER_EVENT_TYPE_ADD;
+ ev.volume = EINA_TRUE;
+ eet_connection_send(ec, es_edd, &ev, NULL);
+ }
+}
+
+static Eina_Bool
+es_read(const void *eet_data __UNUSED__, size_t size __UNUSED__, void *user_data __UNUSED__)
+{
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+cl_add(void *data __UNUSED__, int type __UNUSED__, Ecore_Con_Event_Client_Add *ev)
+{
+ Eet_Connection *ec;
+ INF("Added client");
+
+ ec = eet_connection_new(es_read, (Eet_Write_Cb*)event_write, ev->client);
+ if (!ec)
+ {
+ ERR("Could not create eet serializer! Lost client!");
+ ecore_con_client_del(ev->client);
+ return ECORE_CALLBACK_RENEW;
+ }
+
+ eina_hash_direct_add(clients, ev->client, ec);
+ cl_setup(ev->client, ec);
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+cl_del(void *data __UNUSED__, int type __UNUSED__, Ecore_Con_Event_Client_Del *ev)
+{
+ Eet_Connection *ec;
+ Eina_Bool d;
+ INF("Removed client");
+ ec = eina_hash_find(clients, ev->client);
+ if (ec)
+ {
+ eet_connection_close(ec, &d);
+ eina_hash_del_by_data(clients, ec);
+ }
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void
+eet_setup(void)
+{
+ Eet_Data_Descriptor_Class eddc;
+
+ if (!eet_eina_stream_data_descriptor_class_set(&eddc, sizeof(eddc), "eeze_scanner_event", sizeof(Eeze_Scanner_Event)))
+ {
+ CRI("Could not create eet data descriptor!");
+ exit(1);
+ }
+
+ es_edd = eet_data_descriptor_stream_new(&eddc);
+#define DAT(MEMBER, TYPE) EET_DATA_DESCRIPTOR_ADD_BASIC(es_edd, Eeze_Scanner_Event, #MEMBER, MEMBER, EET_T_##TYPE)
+ DAT(device, INLINED_STRING);
+ DAT(type, UINT);
+ DAT(volume, UCHAR);
+#undef DAT
+}
+
+static Eina_Bool
+cdrom_timer(Eeze_Scanner_Device *dev)
+{
+ const char *devpath;
+ int fd;
+
+ /* cdrom already mounted, no need to poll */
+ if (dev->mounted) return EINA_TRUE;
+ devpath = eeze_udev_syspath_get_devpath(dev->device);
+ fd = open(devpath, O_RDONLY);
+ if (fd < 0)
+ {
+ Eina_List *l;
+
+ l = eina_list_data_find_list(volume_cdrom, dev);
+ if (l)
+ {
+ /* disc removed, delete volume */
+ INF("Removed cdrom '%s'", dev->device);
+ volume_cdrom = eina_list_remove_list(volume_cdrom, l);
+ event_send(dev->device, EEZE_SCANNER_EVENT_TYPE_CHANGE, EINA_TRUE);
+ }
+ /* just in case */
+ dev->mounted = EINA_FALSE;
+ }
+ else
+ {
+ if (!eina_list_data_find(volume_cdrom, dev))
+ {
+ INF("Added cdrom '%s'", dev->device);
+ volume_cdrom = eina_list_append(volume_cdrom, dev);
+ event_send(dev->device, EEZE_SCANNER_EVENT_TYPE_CHANGE, EINA_TRUE);
+ }
+ close(fd);
+ }
+ eina_stringshare_del(devpath);
+ return EINA_TRUE;
+}
+
+static void
+storage_setup(void)
+{
+ Eina_List *l, *ll;
+ const char *sys;
+
+ storage_devices = eeze_udev_find_by_type(EEZE_UDEV_TYPE_DRIVE_INTERNAL, NULL);
+ if (!storage_devices)
+ {
+ ERR("No storage devices found! This is not supposed to happen!");
+ exit(1);
+ }
+ EINA_LIST_FOREACH(storage_devices, l, sys)
+ event_send(sys, EEZE_SCANNER_EVENT_TYPE_ADD, EINA_FALSE);
+
+ ll = eeze_udev_find_by_type(EEZE_UDEV_TYPE_DRIVE_REMOVABLE, NULL);
+ EINA_LIST_FREE(ll, sys)
+ {
+ event_send(sys, EEZE_SCANNER_EVENT_TYPE_ADD, EINA_FALSE);
+ storage_devices = eina_list_append(storage_devices, sys);
+ }
+
+ l = eeze_udev_find_by_type(EEZE_UDEV_TYPE_DRIVE_CDROM, NULL);
+ EINA_LIST_FREE(l, sys)
+ {
+ Eeze_Scanner_Device *dev;
+ Eeze_Disk *disk;
+
+ dev = calloc(1, sizeof(Eeze_Scanner_Device));
+ if (!dev)
+ {
+ ERR("Lost cdrom device '%s'!", sys);
+ eina_stringshare_del(sys);
+ continue;
+ }
+ disk = eeze_disk_new(sys);
+ if (!disk)
+ {
+ ERR("Lost cdrom device '%s'!", sys);
+ eina_stringshare_del(sys);
+ free(dev);
+ continue;
+ }
+ dev->device = sys;
+ dev->mounted = eeze_disk_mounted_get(disk);
+ eeze_disk_free(disk);
+ event_send(sys, EEZE_SCANNER_EVENT_TYPE_ADD, EINA_FALSE);
+ ecore_poller_add(ECORE_POLLER_CORE, 32, (Ecore_Task_Cb)cdrom_timer, dev);
+ storage_cdrom = eina_list_append(storage_cdrom, dev);
+ }
+ volume_devices = eeze_udev_find_by_type(EEZE_UDEV_TYPE_DRIVE_MOUNTABLE, NULL);
+ EINA_LIST_FOREACH_SAFE(volume_devices, l, ll, sys)
+ {
+ Eina_List *c;
+ Eeze_Scanner_Device *dev;
+
+ EINA_LIST_FOREACH(storage_cdrom, c, dev)
+ if (sys == dev->device)
+ {
+ eina_stringshare_del(sys);
+ volume_devices = eina_list_remove_list(volume_devices, l);
+ volume_cdrom = eina_list_append(volume_cdrom, dev);
+ event_send(sys, EEZE_SCANNER_EVENT_TYPE_ADD, EINA_TRUE);
+ l = NULL;
+ break;
+ }
+ if (!l) continue;
+ event_send(sys, EEZE_SCANNER_EVENT_TYPE_ADD, EINA_TRUE);
+ }
+}
+
+static void
+cb_vol_chg(const char *device, Eeze_Udev_Event ev, void *data __UNUSED__, Eeze_Udev_Watch *watch __UNUSED__)
+{
+ Eina_List *l;
+ Eeze_Scanner_Device *dev;
+
+ DBG("device='%s'", device);
+
+ if (ev == EEZE_UDEV_EVENT_ONLINE) ev = EEZE_SCANNER_EVENT_TYPE_ADD;
+ else if (ev == EEZE_UDEV_EVENT_OFFLINE) ev = EEZE_SCANNER_EVENT_TYPE_REMOVE;
+
+ event_send(device, ev, EINA_TRUE);
+ switch (ev)
+ {
+ case EEZE_UDEV_EVENT_ADD:
+ case EEZE_UDEV_EVENT_ONLINE:
+ INF("Added volume '%s'", device);
+ EINA_LIST_FOREACH(storage_cdrom, l, dev)
+ if (device == dev->device)
+ {
+ volume_cdrom = eina_list_append(volume_cdrom, dev);
+ return;
+ }
+ volume_devices = eina_list_append(volume_devices, eina_stringshare_add(device));
+ break;
+ case EEZE_UDEV_EVENT_REMOVE:
+ case EEZE_UDEV_EVENT_OFFLINE:
+ INF("Removed volume '%s'", device);
+ EINA_LIST_FOREACH(volume_cdrom, l, dev)
+ if (device == dev->device)
+ {
+ volume_cdrom = eina_list_remove_list(volume_cdrom, l);
+ return;
+ }
+ volume_devices = eina_list_remove(volume_devices, device);
+ eina_stringshare_del(device);
+ default:
+ break;
+ }
+}
+
+static void
+cb_stor_chg(const char *device, Eeze_Udev_Event ev, void *data __UNUSED__, Eeze_Udev_Watch *watch __UNUSED__)
+{
+ Eina_List *l;
+ Eeze_Scanner_Device *dev = NULL;
+ const char *str;
+
+
+ DBG("device='%s'", device);
+ switch (ev)
+ {
+ case EEZE_UDEV_EVENT_ADD:
+ case EEZE_UDEV_EVENT_ONLINE:
+ INF("Added device '%s'", device);
+ event_send(device, ev, EINA_FALSE);
+ str = eeze_udev_syspath_get_property(device, "ID_CDROM");
+ if (!str)
+ {
+ storage_devices = eina_list_append(storage_devices, eina_stringshare_add(device));
+ return;
+ }
+ eina_stringshare_del(str);
+ dev = calloc(1, sizeof(Eeze_Scanner_Device));
+ dev->device = eina_stringshare_add(device);
+ storage_cdrom = eina_list_append(storage_cdrom, dev);
+ break;
+ case EEZE_UDEV_EVENT_REMOVE:
+ case EEZE_UDEV_EVENT_OFFLINE:
+ if (!eina_list_data_find(storage_devices, device))
+ {
+ EINA_LIST_FOREACH(storage_cdrom, l, dev)
+ if (dev->device == device) break;
+ if ((!dev) || (dev->device != device)) return;
+ }
+ INF("Removed device '%s'", device);
+ event_send(device, ev, EINA_FALSE);
+ EINA_LIST_FOREACH(storage_cdrom, l, dev)
+ if (device == dev->device)
+ {
+ storage_cdrom = eina_list_remove_list(storage_cdrom, l);
+ eina_stringshare_del(dev->device);
+ free(dev);
+ return;
+ }
+ storage_devices = eina_list_remove(storage_devices, device);
+ eina_stringshare_del(device);
+ default:
+ break;
+ }
+}
+
+static void
+es_exit(int sig)
+{
+ const char *tmp;
+ char buf[1024];
+ struct stat st;
+ ecore_con_server_del(svr);
+
+ tmp = getenv("TMPDIR");
+ if (!tmp) tmp = "/tmp";
+
+ snprintf(buf, sizeof(buf), "%s/.ecore_service|eeze_scanner|0", tmp);
+ if (!stat(buf, &st))
+ unlink(buf);
+ exit(sig);
+}
+
+static void
+sigs_setup(void)
+{
+ sigset_t sigs = {{0}};
+ struct sigaction s;
+
+ sigfillset(&sigs);
+ sigdelset(&sigs, SIGSEGV);
+ sigdelset(&sigs, SIGTERM);
+ sigdelset(&sigs, SIGINT);
+ sigdelset(&sigs, SIGQUIT);
+
+ s.sa_handler = es_exit;
+ s.sa_flags = 0;
+ sigaction(SIGTERM, &s, NULL);
+ sigaction(SIGSEGV, &s, NULL);
+ sigaction(SIGINT, &s, NULL);
+}
+
+int
+main(void)
+{
+ const char *tmp;
+ char buf[128], buf2[128];
+ struct stat st;
+
+ eina_init();
+ ecore_init();
+ ecore_con_init();
+ eeze_init();
+ eeze_disk_function();
+ eeze_mount_tabs_watch();
+
+ sigs_setup();
+ es_log_dom = eina_log_domain_register("eeze_scanner", EINA_COLOR_CYAN);
+
+ tmp = getenv("TMPDIR");
+ if (!tmp) tmp = "/tmp";
+
+ snprintf(buf, sizeof(buf), "%s/.ecore_service|eeze_scanner", tmp);
+ snprintf(buf2, sizeof(buf), "%s/.ecore_service|eeze_scanner|0", tmp);
+ if (!stat(buf2, &st))
+ {
+ ERR("Socket file '%s' for scanner already exists! Refusing to start up!", buf);
+ exit(1);
+ }
+ eet_setup();
+ clients = eina_hash_pointer_new(NULL);
+ EINA_SAFETY_ON_NULL_GOTO(clients, error);
+
+ ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_ADD, (Ecore_Event_Handler_Cb)cl_add, NULL);
+ ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DEL, (Ecore_Event_Handler_Cb)cl_del, NULL);
+ ecore_event_handler_add(EEZE_EVENT_DISK_UNMOUNT, (Ecore_Event_Handler_Cb)disk_mount, NULL);
+ ecore_event_handler_add(EEZE_EVENT_DISK_MOUNT, (Ecore_Event_Handler_Cb)disk_mount, NULL);
+
+ eeze_udev_watch_add(EEZE_UDEV_TYPE_DRIVE_INTERNAL, EEZE_UDEV_EVENT_NONE, cb_stor_chg, NULL);
+ eeze_udev_watch_add(EEZE_UDEV_TYPE_DRIVE_REMOVABLE, EEZE_UDEV_EVENT_NONE, cb_stor_chg, NULL);
+ eeze_udev_watch_add(EEZE_UDEV_TYPE_DRIVE_CDROM, EEZE_UDEV_EVENT_NONE, cb_stor_chg, NULL);
+ eeze_udev_watch_add(EEZE_UDEV_TYPE_DRIVE_MOUNTABLE, EEZE_UDEV_EVENT_NONE, cb_vol_chg, NULL);
+
+ svr = ecore_con_server_add(ECORE_CON_LOCAL_SYSTEM, buf, 0, NULL);
+ EINA_SAFETY_ON_NULL_GOTO(svr, error);
+ if (chmod(buf2, S_IRWXU | S_IRWXG | S_IRWXO))
+ {
+ ERR("Could not chmod socket (%s)! \"%s\"", buf, strerror(errno));
+ goto error;
+ }
+
+ storage_setup();
+ ecore_main_loop_begin();
+
+ ecore_con_server_del(svr);
+ return 0;
+error:
+ ERR("Could not start up!");
+ exit(1);
+}
diff --git a/src/bin/eeze_scanner.h b/src/bin/eeze_scanner.h
new file mode 100644
index 0000000..54320eb
--- /dev/null
+++ b/src/bin/eeze_scanner.h
@@ -0,0 +1,32 @@
+#ifndef EEZE_SCANNER_H
+#define EEZE_SCANNER_H
+
+#include <Eeze.h>
+
+#define EEZE_SCANNER_EDD_SETUP(edd) \
+ EET_DATA_DESCRIPTOR_ADD_BASIC((edd), Eeze_Scanner_Event, "device", device, EET_T_INLINED_STRING); \
+ EET_DATA_DESCRIPTOR_ADD_BASIC((edd), Eeze_Scanner_Event, "type", type, EET_T_UINT); \
+ EET_DATA_DESCRIPTOR_ADD_BASIC((edd), Eeze_Scanner_Event, "volume", volume, EET_T_UCHAR)
+
+typedef enum
+{
+ EEZE_SCANNER_EVENT_TYPE_NONE,
+ EEZE_SCANNER_EVENT_TYPE_ADD = EEZE_UDEV_EVENT_ADD,
+ EEZE_SCANNER_EVENT_TYPE_REMOVE = EEZE_UDEV_EVENT_REMOVE,
+ EEZE_SCANNER_EVENT_TYPE_CHANGE = EEZE_UDEV_EVENT_CHANGE
+} Eeze_Scanner_Event_Type;
+
+typedef struct
+{
+ const char *device;
+ Eeze_Scanner_Event_Type type;
+ Eina_Bool volume;
+} Eeze_Scanner_Event;
+
+typedef struct
+{
+ const char *device;
+ Eina_Bool mounted : 1;
+} Eeze_Scanner_Device;
+
+#endif
diff --git a/src/bin/eeze_udev_test.c b/src/bin/eeze_udev_test.c
new file mode 100644
index 0000000..130771a
--- /dev/null
+++ b/src/bin/eeze_udev_test.c
@@ -0,0 +1,238 @@
+#include <Eeze.h>
+#include <Ecore.h>
+#include <stdio.h>
+
+/**
+ * This demo program shows how to use some eeze_udev functions. It roughly
+ * 1kb as of now, TODO is to fix this but I'm too lazy now and it's only
+ * a demo.
+ */
+
+typedef struct kbdmouse
+{
+ Eina_List *kbds;
+ Eina_List *mice;
+ Eina_Hash *hash;
+} kbdmouse;
+
+static void
+/* event will always be a syspath starting with /sys */
+catch_events(const char *device,
+ Eeze_Udev_Event event,
+ void *data,
+ Eeze_Udev_Watch *watch)
+{
+ kbdmouse *akbdmouse = data;
+ Eina_List *l;
+ const char *name, *dev, *type;
+
+ /* the device that comes through will be prefixed by "/sys"
+ * but the saved name will not, so we check for the saved name
+ * inside the device name
+ */
+ EINA_LIST_FOREACH(akbdmouse->kbds, l, name)
+ if (!strncmp(device + 5, name, strlen(device + 5) - 8)) goto end;
+ EINA_LIST_FOREACH(akbdmouse->mice, l, name)
+ if (!strncmp(device + 5, name, strlen(device + 5) - 8)) goto end;
+
+ /* check to see if the device was just plugged in */
+ if (eeze_udev_syspath_is_kbd(device) || eeze_udev_syspath_is_mouse(device))
+ goto end;
+ /* if we reach here, the device is neither a keyboard nor a mouse that we saw
+ * previously, so we print a moderately amusing message and bail
+ */
+ printf("Sneaky sneaky! But %s is not a keyboard or a mouse!!\n", device);
+ return;
+
+end:
+ /* we stored the devpaths for all the syspaths previously so that
+ * we can retrieve them now even though the device has been removed and
+ * is inaccessible to udev
+ */
+ if ((event & EEZE_UDEV_EVENT_ADD) == EEZE_UDEV_EVENT_ADD)
+ {
+ dev = eeze_udev_syspath_get_devpath(device);
+ type = "plugged in";
+ }
+ else
+ {
+ dev = eina_hash_find(akbdmouse->hash, name);
+ type = "unplugged";
+ }
+ printf("You %s %s!\n", type, dev);
+ printf("All tests completed, exiting successfully!\n");
+ /* and the hash */
+ eina_hash_free(akbdmouse->hash);
+ /* now we free the lists */
+ eina_list_free(akbdmouse->kbds);
+ eina_list_free(akbdmouse->mice);
+ /* and the random storage struct */
+ free(akbdmouse);
+ /* and delete the watch */
+ eeze_udev_watch_del(watch);
+ /* and shut down eudev */
+ eeze_shutdown();
+ /* and quit the main loop */
+ ecore_main_loop_quit();
+}
+
+static void
+hash_free(void *data)
+{
+ eina_stringshare_del(data);
+}
+
+int
+main()
+{
+ Eina_List *type, *l;
+ const char *name, *check, *check2;
+ kbdmouse *akbdmouse;
+ Eina_Hash *hash;
+
+ ecore_init();
+ eeze_init();
+
+ hash = eina_hash_stringshared_new(hash_free);
+ akbdmouse = malloc(sizeof(kbdmouse));
+ akbdmouse->hash = hash;
+
+ printf("For my first trick, I will find all of your keyboards and return their syspaths.\n");
+ /* find all keyboards using type EEZE_UDEV_TYPE_KEYBOARD */
+ type = eeze_udev_find_by_type(EEZE_UDEV_TYPE_KEYBOARD, NULL);
+ /* add all "link" devices that aren't explicitly found, but are still
+ * part of the device chain
+ */
+ type = eeze_udev_find_unlisted_similar(type);
+ EINA_LIST_FOREACH(type, l, name)
+ {
+ /* add the devpath to the hash for use in the cb later */
+ if ((check = eeze_udev_syspath_get_devpath(name)))
+ eina_hash_direct_add(hash, name, check);
+ printf("Found keyboard: %s\n", name);
+ }
+ /* we save this list for later, because once a device is unplugged it can
+ * no longer be detected by udev, and any related properties are unusable unless
+ * they have been previously stored
+ */
+ akbdmouse->kbds = type;
+
+ printf("\nNext, I will find all of your mice and print the corresponding manufacturer.\n");
+ /* find all mice using type EEZE_UDEV_TYPE_MOUSE */
+ type = eeze_udev_find_by_type(EEZE_UDEV_TYPE_MOUSE, NULL);
+ type = eeze_udev_find_unlisted_similar(type);
+ EINA_LIST_FOREACH(type, l, name)
+ { /* add the devpath to the hash for use in the cb later */
+ if ((check = eeze_udev_syspath_get_devpath(name)))
+ eina_hash_direct_add(hash, name, check); /* get a property using the device's syspath */
+ printf("Found mouse %s with vendor: %s\n", name, eeze_udev_walk_get_sysattr(name, "manufacturer"));
+ }
+ /* we save this list for later, because once a device is unplugged it can
+ * no longer be detected by udev, and any related properties are unusable unless
+ * they have been previously stored
+ */
+ akbdmouse->mice = type;
+
+ printf("\nNow let's try something a little more difficult. Mountable filesystems!\n");
+ /* find all mountable drives using type EEZE_UDEV_TYPE_DRIVE_MOUNTABLE */
+ type = eeze_udev_find_by_type(EEZE_UDEV_TYPE_DRIVE_MOUNTABLE, NULL);
+ type = eeze_udev_find_unlisted_similar(type);
+ EINA_LIST_FREE(type, name)
+ {
+ printf("Found device: %s\n", name); /* get a property using the device's syspath */
+ if ((check = eeze_udev_syspath_get_property(name, "DEVNAME")))
+ {
+ printf("\tYou probably know it better as %s\n", check);
+ eina_stringshare_del(check);
+ }
+ if ((check = eeze_udev_syspath_get_property(name, "ID_FS_TYPE")))
+ {
+ printf("\tIt's formatted as %s", check);
+ eina_stringshare_del(check);
+ check = eeze_udev_syspath_get_property(name, "FSTAB_DIR");
+ if (check)
+ {
+ printf(", and gets mounted at %s", check);
+ eina_stringshare_del(check);
+ }
+ printf("!\n");
+ }
+ eina_stringshare_del(name);
+ }
+
+ printf("\nNetwork devices!\n");
+ type = eeze_udev_find_by_type(EEZE_UDEV_TYPE_NET, NULL);
+ type = eeze_udev_find_unlisted_similar(type);
+ EINA_LIST_FREE(type, name)
+ {
+ printf("Found device: %s\n", name); /* get a property using the device's syspath */
+ if ((check = eeze_udev_syspath_get_property(name, "INTERFACE")))
+ {
+ printf("\tYou probably know it better as %s\n", check);
+ eina_stringshare_del(check);
+ }
+ eina_stringshare_del(name);
+ }
+
+ printf("\nInternal drives, anyone? With serial numbers?\n");
+ /* find all internal drives using type EEZE_UDEV_TYPE_DRIVE_INTERNAL */
+ type = eeze_udev_find_by_type(EEZE_UDEV_TYPE_DRIVE_INTERNAL, NULL);
+ type = eeze_udev_find_unlisted_similar(type);
+ EINA_LIST_FREE(type, name) /* get a property using the device's syspath */
+ {
+ if ((check = eeze_udev_syspath_get_property(name, "ID_SERIAL")))
+ {
+ printf("%s: %s\n", name, check);
+ eina_stringshare_del(check);
+ }
+ eina_stringshare_del(name);
+ }
+
+ printf("\nGot any removables? I'm gonna find em!\n");
+ /* find all removable media using type EEZE_UDEV_TYPE_DRIVE_REMOVABLE */
+ type = eeze_udev_find_by_type(EEZE_UDEV_TYPE_DRIVE_REMOVABLE, NULL);
+ type = eeze_udev_find_unlisted_similar(type);
+ EINA_LIST_FREE(type, name) /* get a property using the device's syspath */
+ {
+ if ((check = eeze_udev_syspath_get_sysattr(name, "model")))
+ {
+ check2 = eeze_udev_syspath_get_subsystem(name);
+ printf("\tOoh, a %s attached to the %s subsytem!\n", check, check2);
+ eina_stringshare_del(check);
+ eina_stringshare_del(check2);
+ }
+ eina_stringshare_del(name);
+ }
+
+ printf("\nGot any v4l device ?\n");
+ /* find all V4L device, may be a webcam or anything that can get a video
+ * stream from the real worl in a numerical form */
+ type = eeze_udev_find_by_type(EEZE_UDEV_TYPE_V4L, NULL);
+ type = eeze_udev_find_unlisted_similar(type);
+ EINA_LIST_FREE(type, name) /* get a device name using the device's syspath */
+ {
+ if ((check = eeze_udev_syspath_get_property(name, "DEVNAME")))
+ {
+ if ((check2 = eeze_udev_syspath_get_sysattr(name, "name")))
+ {
+ printf("%s: '%s' [%s]\n", name, check2, check);
+ eina_stringshare_del(check2);
+ }
+ eina_stringshare_del(check);
+ }
+ eina_stringshare_del(name);
+ }
+
+ /* set a udev watch, grab all events because no EEZE_UDEV_TYPE filter is specified,
+ * set the events to be sent to callback function catch_events(), and attach
+ * kbdmouse to the watch as associated data
+ */
+ eeze_udev_watch_add(EEZE_UDEV_TYPE_NONE, (EEZE_UDEV_EVENT_ADD | EEZE_UDEV_EVENT_REMOVE), catch_events, akbdmouse);
+ printf("\nAnd now for something more complicated. Plug or unplug your keyboard or mouse for me.\n");
+
+ /* main loop must be started to use ecore fd polling */
+ ecore_main_loop_begin();
+
+ return 0;
+}
+
diff --git a/src/bin/eeze_umount.c b/src/bin/eeze_umount.c
new file mode 100644
index 0000000..75d5ebb
--- /dev/null
+++ b/src/bin/eeze_umount.c
@@ -0,0 +1,113 @@
+#include <Eeze.h>
+#include <Eeze_Disk.h>
+#include <Ecore.h>
+#include <Ecore_File.h>
+#include <Ecore_Getopt.h>
+#include <stdio.h>
+
+/** This app can be used as a "dumb" replacement for unmount. Just don't try anything fancy yet! */
+static const Ecore_Getopt opts =
+{
+ "eeze_unmount",
+ "eeze_unmount /dev/sdb1 /media/disk",
+ "1.0",
+ "(C) 2010 Mike Blumenkrantz",
+ "LGPL",
+ "unmount a disk using either its /sys/ path or its /dev/ path\n\n",
+ 1,
+ {
+ ECORE_GETOPT_STORE_TRUE('v', "verbose", "Enable debug output"),
+ ECORE_GETOPT_VERSION('V', "version"),
+ ECORE_GETOPT_COPYRIGHT('R', "copyright"),
+ ECORE_GETOPT_LICENSE('L', "license"),
+ ECORE_GETOPT_HELP('h', "help"),
+ ECORE_GETOPT_SENTINEL
+ }
+};
+
+void
+_unmount_cb(void *data, int type, Eeze_Event_Disk_Unmount *e)
+{
+ (void)data;
+ (void)type;
+ printf("Success!\n");
+ eeze_disk_free(e->disk);
+ ecore_main_loop_quit();
+}
+
+void
+_error_cb(void *data, int type, Eeze_Event_Disk_Error *de)
+{
+ (void)data;
+ (void)type;
+ printf("Could not unmount disk with /dev/ path: %s!\n", eeze_disk_devpath_get(de->disk));
+ eeze_disk_free(de->disk);
+ ecore_main_loop_quit();
+}
+
+int
+main(int argc, char *argv[])
+{
+ int args;
+ const char *dev;
+ Eina_Bool verbose = EINA_FALSE, exit_option = EINA_FALSE;
+ Eeze_Disk *disk;
+
+ Ecore_Getopt_Value values[] =
+ {
+ ECORE_GETOPT_VALUE_BOOL(verbose),
+ ECORE_GETOPT_VALUE_BOOL(exit_option),
+ ECORE_GETOPT_VALUE_BOOL(exit_option),
+ ECORE_GETOPT_VALUE_BOOL(exit_option),
+ ECORE_GETOPT_VALUE_BOOL(exit_option)
+ };
+
+ if (argc < 2)
+ {
+ printf("Insufficient args specified!\n");
+ ecore_getopt_help(stderr, &opts);
+ exit(1);
+ }
+
+ ecore_init();
+ eeze_init();
+ ecore_app_args_set(argc, (const char **)argv);
+ args = ecore_getopt_parse(&opts, values, argc, argv);
+
+ if (exit_option)
+ return 0;
+
+ if (args < 0)
+ {
+ printf("No args specified!\n");
+ ecore_getopt_help(stderr, &opts);
+ exit(1);
+ }
+ if (verbose) eina_log_domain_level_set("eeze_disk", EINA_LOG_LEVEL_DBG);
+ dev = argv[args];
+ if ((!strncmp(dev, "/sys/", 5)) || (!strncmp(dev, "/dev/", 5)))
+ disk = eeze_disk_new(dev);
+ else if ((args == argc - 1) && (ecore_file_is_dir(dev)))
+ disk = eeze_disk_new_from_mount(dev);
+ else
+ {
+ printf("[Device] must be either a /dev/ path or a /sys/ path!\n");
+ ecore_getopt_help(stderr, &opts);
+ exit(1);
+ }
+ if (!eeze_disk_mounted_get(disk))
+ {
+ printf("[%s] is already unmounted!", dev);
+ exit(1);
+ }
+ ecore_event_handler_add(EEZE_EVENT_DISK_UNMOUNT, (Ecore_Event_Handler_Cb)_unmount_cb, NULL);
+ ecore_event_handler_add(EEZE_EVENT_DISK_ERROR, (Ecore_Event_Handler_Cb)_error_cb, NULL);
+ if (!eeze_disk_unmount(disk))
+ {
+ printf("unmount operation could not be started!\n");
+ exit(1);
+ }
+ ecore_main_loop_begin();
+
+ return 0;
+}
diff --git a/src/lib/Eeze.h b/src/lib/Eeze.h
new file mode 100644
index 0000000..5ed01a7
--- /dev/null
+++ b/src/lib/Eeze.h
@@ -0,0 +1,560 @@
+/**
+ @brief Eeze Device Library
+ *
+ @mainpage Eeze
+ @image html eeze.png
+ @version 1.2.0
+ @author Mike Blumenkrantz (zmike/discomfitor) <michael.blumenkrantz@@gmail.com>
+ @date 2010-2012
+
+ @section intro What is Eeze?
+
+ Eeze is a library for manipulating devices through udev with a simple and fast
+ api. It interfaces directly with libudev, avoiding such middleman daemons as
+ udisks/upower or hal, to immediately gather device information the instant it
+ becomes known to the system. This can be used to determine such things as:
+ @li If a cdrom has a disk inserted
+ @li The temperature of a cpu core
+ @li The remaining power left in a battery
+ @li The current power consumption of various parts
+ @li Monitor in realtime the status of peripheral devices
+
+ Each of the above examples can be performed by using only a single eeze
+ function, as one of the primary focuses of the library is to reduce the
+ complexity of managing devices.
+
+ @li @link Eeze.h Eeze functions @endlink
+ @li @ref udev UDEV functions
+ @li @ref watch Functions that watch for events
+ @li @ref syspath Functions that accept a device /sys/ path
+ @li @ref find Functions which find types of devices
+ @li @ref disk Disk functions
+ @li @ref net Net functions
+ @verbatim
+ Pants
+ @endverbatim
+ */
+#ifndef EEZE_UDEV_H
+#define EEZE_UDEV_H
+
+#include <Eina.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+#else
+# define EAPI
+#endif
+
+/**
+ * @file Eeze.h
+ * @brief Easy device manipulation.
+ *
+ * Eeze is a library for manipulating devices through udev with a simple and fast
+ * api. It interfaces directly with libudev, avoiding such middleman daemons as
+ * udisks/upower or hal, to immediately gather device information the instant it
+ * becomes known to the system. This can be used to determine such things as:
+ * @li If a cdrom has a disk inserted
+ * @li The temperature of a cpu core
+ * @li The remaining power left in a battery
+ * @li The current power consumption of various parts
+ * @li Monitor in realtime the status of peripheral devices
+ * Each of the above examples can be performed by using only a single eeze
+ * function, as one of the primary focuses of the library is to reduce the
+ * complexity of managing devices.
+ *
+ *
+ * For udev functions, see @ref udev.
+ */
+
+/**
+ * @defgroup main main
+ *
+ * These are general eeze functions which include init and shutdown.
+ */
+
+/**
+ * @defgroup udev udev
+ *
+ * These are functions which interact directly with udev.
+ */
+
+/**
+ * @addtogroup udev
+ *
+ * These are the device subsystems of udev:
+ * @li ac97
+ * @li acpi
+ * @li bdi
+ * @li block
+ * @li bsg
+ * @li dmi
+ * @li graphics
+ * @li hid
+ * @li hwmon
+ * @li i2c
+ * @li input
+ * @li mem
+ * @li misc
+ * @li net
+ * @li pci
+ * @li pci_bus
+ * @li pci_express
+ * @li platform
+ * @li pnp
+ * @li rtc
+ * @li scsi
+ * @li scsi_device
+ * @li scsi_disk
+ * @li scsi_generic
+ * @li scsi_host
+ * @li serio
+ * @li sound
+ * @li thermal
+ * @li tty
+ * @li usb
+ * @li usb_device
+ * @li vc
+ * @li vtconsole
+ *
+ * These are the devtypes of udev.
+ * @li atapi
+ * @li audio
+ * @li block
+ * @li cd
+ * @li char
+ * @li disk
+ * @li floppy
+ * @li generic
+ * @li hid
+ * @li hub
+ * @li media
+ * @li optical
+ * @li printer
+ * @li rbc
+ * @li scsi
+ * @li storage
+ * @li tape
+ * @li video
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @addtogroup udev
+ * @typedef Eeze_Udev_Event
+ * @enum Eeze_Udev_Event
+ * @brief Flags for watch events
+ *
+ * These events are used to specify the events to watch in a
+ * #Eeze_Udev_Watch. They can be ORed together.
+ *@{
+ */
+typedef enum
+{
+ /** - No event specified */
+ EEZE_UDEV_EVENT_NONE = 0xf0,
+ /** - Device added */
+ EEZE_UDEV_EVENT_ADD = (1 << 1),
+ /** - Device removed */
+ EEZE_UDEV_EVENT_REMOVE = (1 << 2),
+ /** - Device changed */
+ EEZE_UDEV_EVENT_CHANGE = (1 << 3),
+ /** - Device has come online */
+ EEZE_UDEV_EVENT_ONLINE = (1 << 4),
+ /** - Device has gone offline */
+ EEZE_UDEV_EVENT_OFFLINE = (1 << 5)
+} Eeze_Udev_Event;
+/** @} */
+
+/**
+ * @addtogroup udev udev
+ * @typedef Eeze_Udev_Type Eeze_Udev_Type
+ * @enum Eeze_Udev_Type
+ * @brief Convenience types to simplify udev access.
+ *
+ * These types allow easy access to certain udev device types. They
+ * may only be used in specified functions.
+ *
+ * @{
+ */
+/*FIXME: these probably need to be bitmasks with categories*/
+typedef enum
+{
+ /** - No type */
+ EEZE_UDEV_TYPE_NONE,
+ /** - Keyboard device */
+ EEZE_UDEV_TYPE_KEYBOARD,
+ /** - Mouse device */
+ EEZE_UDEV_TYPE_MOUSE,
+ /** - Touchpad device */
+ EEZE_UDEV_TYPE_TOUCHPAD,
+ /** - Mountable drive */
+ EEZE_UDEV_TYPE_DRIVE_MOUNTABLE,
+ /** - Internal drive */
+ EEZE_UDEV_TYPE_DRIVE_INTERNAL,
+ /** - Removable drive */
+ EEZE_UDEV_TYPE_DRIVE_REMOVABLE,
+ /** - cd drive */
+ EEZE_UDEV_TYPE_DRIVE_CDROM,
+ /** - AC adapter */
+ EEZE_UDEV_TYPE_POWER_AC,
+ /** - Battery */
+ EEZE_UDEV_TYPE_POWER_BAT,
+ /** - Temperature sensor */
+ EEZE_UDEV_TYPE_IS_IT_HOT_OR_IS_IT_COLD_SENSOR,
+ /** - Network devices */
+ EEZE_UDEV_TYPE_NET,
+ /** - WebCam */
+ EEZE_UDEV_TYPE_V4L,
+ /** - Bluetooth */
+ EEZE_UDEV_TYPE_BLUETOOTH,
+ /** - Joystick
+ * @since 1.3
+ */
+ EEZE_UDEV_TYPE_JOYSTICK
+} Eeze_Udev_Type;
+/**@}*/
+
+struct Eeze_Udev_Watch;
+
+/**
+ * @addtogroup watch
+ * @typedef Eeze_Udev_Watch Eeze_Udev_Watch
+ * @brief Opaque structure to hold data for a udev watch
+ */
+typedef struct Eeze_Udev_Watch Eeze_Udev_Watch;
+
+#define EEZE_VERSION_MAJOR 1
+#define EEZE_VERSION_MINOR 2
+
+ typedef struct _Eeze_Version
+ {
+ int major;
+ int minor;
+ int micro;
+ int revision;
+ } Eeze_Version;
+
+ EAPI extern Eeze_Version *eeze_version;
+
+/**
+ * @addtogroup watch
+ * @typedef Eeze_Udev_Watch_Cb Eeze_Udev_Watch_Cb
+ * @brief Callback type for use with #Eeze_Udev_Watch
+ */
+typedef void(*Eeze_Udev_Watch_Cb)(const char *, Eeze_Udev_Event, void *, Eeze_Udev_Watch *);
+
+
+/**
+ * Initialize the eeze library.
+ * @return The number of times the function has been called, or -1 on failure.
+ *
+ * This function should be called prior to using any eeze functions, and MUST
+ * be called prior to using any udev functions to avoid a segv.
+ *
+ * @ingroup main
+ */
+EAPI int eeze_init(void);
+
+/**
+ * Shut down the eeze library.
+ * @return The number of times the eeze_init has been called, or -1 when
+ * all occurrences of eeze have been shut down.
+ *
+ * This function should be called when no further eeze functions will be called.
+ *
+ * @ingroup main
+ */
+EAPI int eeze_shutdown(void);
+
+ /**
+ * @addtogroup find Find
+ *
+ * These are functions which find/supplement lists of devices.
+ *
+ * @ingroup udev
+ *
+ * @{
+ */
+
+/**
+ * Returns a stringshared list of all syspaths that are (or should be) the same
+ * device as the device pointed at by @p syspath.
+ *
+ * @param syspath The syspath of the device to find matches for
+ * @return All devices which are the same as the one passed
+ */
+EAPI Eina_List *eeze_udev_find_similar_from_syspath(const char *syspath);
+
+/**
+ * Updates a list of all syspaths that are (or should be) the same
+ * device.
+ *
+ * @param list The list of devices to update
+ * @return The updated list
+ *
+ * This function will update @p list to include all devices matching
+ * devices with syspaths currently stored in @p list. All strings are
+ * stringshared.
+ *
+ * @note This is an expensive call, do not use it unless you must.
+ */
+EAPI Eina_List *eeze_udev_find_unlisted_similar(Eina_List *list);
+
+/**
+ * Find a list of devices by a sysattr (and, optionally, a value of that sysattr).
+ *
+ * @param sysattr The attribute to find
+ * @param value Optional: the value that the attribute should have
+ *
+ * @return A stringshared list of the devices found with the attribute
+ *
+ * @ingroup find
+ */
+EAPI Eina_List *eeze_udev_find_by_sysattr(const char *sysattr, const char *value);
+
+/**
+ * Find devices using an #Eeze_Udev_Type and/or a name.
+ *
+ * @param type An #Eeze_Udev_Type or 0
+ * @param name A filter for the device name or @c NULL
+ * @return A stringshared Eina_List of matched devices or @c NULL on failure
+ *
+ * Return a list of syspaths (/sys/$syspath) for matching udev devices.
+ */
+EAPI Eina_List *eeze_udev_find_by_type(Eeze_Udev_Type type, const char *name);
+
+/**
+ * A more advanced find, allows finds using udev properties.
+ *
+ * @param subsystem The udev subsystem to filter by, or @c NULL
+ * @param type "ID_INPUT_KEY", "ID_INPUT_MOUSE", "ID_INPUT_TOUCHPAD", @c NULL, etc
+ * @param name A filter for the device name, or @c NULL
+ * @return A stringshared Eina_List* of matched devices or @c NULL on failure
+ *
+ * Return a list of syspaths (/sys/$syspath) for matching udev devices.
+ * Requires at least one filter.
+ */
+EAPI Eina_List *eeze_udev_find_by_filter(const char *subsystem, const char *type, const char *name);
+ /**
+ * @}
+ */
+
+ /**
+ * @addtogroup syspath Syspath
+ *
+ * These are functions which interact with the syspath (/sys/$PATH) of
+ * a device.
+ *
+ * @ingroup udev
+ *
+ * @{
+ */
+
+/**
+ * Get the syspath of a device from the /dev/ path.
+ *
+ * @param devpath The /dev/ path of the device
+ * @return A stringshared char* which corresponds to the /sys/ path of the device or @c NULL on failure
+ *
+ * Takes "/dev/path" and returns the corresponding /sys/ path (without the "/sys/")
+ */
+EAPI const char *eeze_udev_devpath_get_syspath(const char *devpath);
+
+/**
+ * Find the root device of a device from its syspath.
+ *
+ * @param syspath The syspath of a device, with or without "/sys/"
+ * @return The syspath of the parent device
+ *
+ * Return a stringshared syspath (/sys/$syspath) for the parent device.
+ */
+EAPI const char *eeze_udev_syspath_get_parent(const char *syspath);
+
+/**
+ * Returns a list of all parent device syspaths for @p syspath.
+ *
+ * @param syspath The device to find parents of
+ * @return A stringshared list of the parent devices of @p syspath
+ */
+EAPI Eina_List *eeze_udev_syspath_get_parents(const char *syspath);
+
+/**
+ * Get the /dev/ path from the /sys/ path.
+ *
+ * @param syspath The /sys/ path with or without the /sys/
+ * @return A stringshared char* with the /dev/ path or @c NULL on failure
+ *
+ * Takes /sys/$PATH and turns it into the corresponding "/dev/x/y".
+ */
+EAPI const char *eeze_udev_syspath_get_devpath(const char *syspath);
+
+/**
+ * Get the /dev/ name from the /sys/ path.
+ *
+ * @param syspath The /sys/ path with or without the /sys/
+ * @return A stringshared char* of the device name without the /dev/ path, or @c NULL on failure
+ *
+ * Takes /sys/$PATH and turns it into the corresponding /dev/x/"y".
+ */
+EAPI const char *eeze_udev_syspath_get_devname(const char *syspath);
+
+/**
+ * Get the subsystem of a device from the /sys/ path.
+ *
+ * @param syspath The /sys/ path with or without the /sys/
+ * @return A stringshared char* with the subsystem of the device or @c NULL on failure
+ *
+ * Takes /sys/$PATH and returns the corresponding device subsystem,
+ * such as "input" for keyboards/mice.
+ */
+EAPI const char *eeze_udev_syspath_get_subsystem(const char *syspath);
+
+/**
+ * Get the property value of a device from the /sys/ path.
+ *
+ * @param syspath The /sys/ path with or without the /sys/
+ * @param property The property to get; full list of these is a FIXME
+ * @return A stringshared char* with the property or @c NULL on failure
+ */
+EAPI const char *eeze_udev_syspath_get_property(const char *syspath, const char *property);
+
+/**
+ * Get the sysattr value of a device from the /sys/ path.
+ *
+ * @param syspath The /sys/ path with or without the /sys/
+ * @param sysattr The sysattr to get; full list of these is a FIXME
+ * @return A stringshared char* with the sysattr or @c NULL on failure
+ */
+EAPI const char *eeze_udev_syspath_get_sysattr(const char *syspath, const char *sysattr);
+
+/**
+ * Checks whether the device is a mouse.
+ *
+ * @param syspath The /sys/ path with or without the /sys/
+ * @return If true, the device is a mouse
+ */
+EAPI Eina_Bool eeze_udev_syspath_is_mouse(const char *syspath);
+
+/**
+ * Checks whether the device is a keyboard.
+ *
+ * @param syspath The /sys/ path with or without the /sys/
+ * @return If true, the device is a keyboard
+ */
+EAPI Eina_Bool eeze_udev_syspath_is_kbd(const char *syspath);
+
+/**
+ * Checks whether the device is a touchpad.
+ *
+ * @param syspath The /sys/ path with or without the /sys/
+ * @return If true, the device is a touchpad
+ */
+EAPI Eina_Bool eeze_udev_syspath_is_touchpad(const char *syspath);
+
+/**
+ * Checks whether the device is a joystick.
+ *
+ * @param syspath The /sys/ path with or without the /sys/
+ * @return If true, the device is a joystick
+ * @since 1.3
+ */
+EAPI Eina_Bool eeze_udev_syspath_is_joystick(const char *syspath);
+ /**
+ * @}
+ */
+
+ /**
+ * @addtogroup walks Walks
+ *
+ * These are functions which walk up the device chain.
+ *
+ * @ingroup udev
+ *
+ * @{
+ */
+
+/**
+ * Walks up the device chain starting at @p syspath,
+ * checking each device for @p sysattr with (optional) @p value.
+ *
+ * @param syspath The /sys/ path of the device to start at, with or without the /sys/
+ * @param sysattr The attribute to find
+ * @param value OPTIONAL: The value that @p sysattr should have, or @c NULL
+ *
+ * @return If the sysattr (with value) is found, returns TRUE. Else, false.
+ */
+EAPI Eina_Bool eeze_udev_walk_check_sysattr(const char *syspath, const char *sysattr, const char *value);
+
+/**
+ * Walks up the device chain starting at @p syspath,
+ * checking each device for @p sysattr, and returns the value if found.
+ *
+ * @param syspath The /sys/ path of the device to start at, with or without the /sys/
+ * @param sysattr The attribute to find
+ *
+ * @return The stringshared value of @p sysattr if found, or @c NULL
+ */
+EAPI const char *eeze_udev_walk_get_sysattr(const char *syspath, const char *sysattr);
+ /**
+ * @}
+ */
+
+ /**
+ * @addtogroup watch Watch
+ *
+ * @brief These are functions which monitor udev for events.
+ *
+ * Eeze watches are simple: you specify a type of device to watch (or all devices), some events (or all) to watch for, a callback,
+ * and some data, and then udev watches those device types for events of the type you specified. Your callback is called with a
+ * syspath of the triggering device and the event that happened to the device, along with the data you associated with the watch and
+ * the watch object itself in case you want to stop the watch easily in a callback.
+ *
+ * @ingroup udev
+ *
+ * @{
+ */
+
+/**
+ * Add a watch for a device type
+ *
+ * @param type The #Eeze_Udev_Type to watch
+ * @param event The events to watch; an OR list of #Eeze_Udev_Event (ie (#EEZE_UDEV_EVENT_ADD | #EEZE_UDEV_EVENT_REMOVE)), or 0 for all events
+ * @param cb The function to call when the watch receives data of type #Eeze_Udev_Watch_Cb
+ * @param user_data Data to pass to the callback function
+ *
+ * @return A watch struct for the watch type specified, or @c NULL on failure
+ *
+ * Eeze watches will monitor udev for changes of type(s) @p event to devices of type @p type. When these changes occur, the stringshared
+ * syspath of the device will be sent to function @p func, along with the bitmask of the event type which can be detected through
+ * binary &.
+ */
+EAPI Eeze_Udev_Watch *eeze_udev_watch_add(Eeze_Udev_Type type, int event, Eeze_Udev_Watch_Cb cb, void *user_data);
+
+/**
+ * Deletes a watch.
+ *
+ * @param watch An Eeze_Udev_Watch object
+ * @return The data originally associated with the watch, or @c NULL
+ *
+ * Deletes a watch, closing file descriptors and freeing related udev memory.
+ */
+EAPI void *eeze_udev_watch_del(Eeze_Udev_Watch *watch);
+ /**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lib/Eeze_Disk.h b/src/lib/Eeze_Disk.h
new file mode 100644
index 0000000..8c402ad
--- /dev/null
+++ b/src/lib/Eeze_Disk.h
@@ -0,0 +1,566 @@
+#ifndef EEZE_DISK_H
+#define EEZE_DISK_H
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+#else
+# define EAPI
+#endif
+
+#include <Eina.h>
+#include <Ecore.h>
+
+/**
+ * @file Eeze_Disk.h
+ * @brief Disk manipulation
+ * @since 1.1
+ *
+ * Eeze disk functions allow you to quickly and efficiently manipulate disks
+ * through simple function calls.
+ *
+ * @addtogroup disk Disk
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @enum Eeze_Disk_Type
+ * @since 1.1
+ *
+ * All disk types known to Eeze.
+ */
+typedef enum
+{
+ EEZE_DISK_TYPE_UNKNOWN = 0, /**< type could not be determined */
+ EEZE_DISK_TYPE_INTERNAL = (1 << 0), /**< internal drive */
+ EEZE_DISK_TYPE_CDROM = (1 << 1), /**< cdrom drive */
+ EEZE_DISK_TYPE_USB = (1 << 2), /**< usb drive */
+ EEZE_DISK_TYPE_FLASH = (1 << 3) /**< flash disk */
+} Eeze_Disk_Type;
+
+/**
+ * @enum Eeze_Mount_Opts
+ * @since 1.1
+ *
+ * All mount options known to Eeze.
+ */
+typedef enum
+{
+#define EEZE_DISK_MOUNTOPT_DEFAULTS (EEZE_DISK_MOUNTOPT_UTF8 | EEZE_DISK_MOUNTOPT_NOEXEC | EEZE_DISK_MOUNTOPT_NOSUID)
+ EEZE_DISK_MOUNTOPT_LOOP = (1 << 1),
+ EEZE_DISK_MOUNTOPT_UTF8 = (1 << 2),
+ EEZE_DISK_MOUNTOPT_NOEXEC = (1 << 3),
+ EEZE_DISK_MOUNTOPT_NOSUID = (1 << 4),
+ EEZE_DISK_MOUNTOPT_REMOUNT = (1 << 5),
+ EEZE_DISK_MOUNTOPT_UID = (1 << 6) /**< use current user's uid */
+} Eeze_Mount_Opts;
+
+
+EAPI extern int EEZE_EVENT_DISK_MOUNT;
+EAPI extern int EEZE_EVENT_DISK_UNMOUNT;
+EAPI extern int EEZE_EVENT_DISK_EJECT;
+EAPI extern int EEZE_EVENT_DISK_ERROR;
+
+typedef struct _Eeze_Event_Disk Eeze_Event_Disk_Mount;
+typedef struct _Eeze_Event_Disk Eeze_Event_Disk_Unmount;
+typedef struct _Eeze_Event_Disk Eeze_Event_Disk_Eject;
+
+/**
+ * @typedef Eeze_Disk
+ * @since 1.1
+ *
+ * Handle for an Eeze Disk.
+ */
+typedef struct _Eeze_Disk Eeze_Disk;
+
+struct _Eeze_Event_Disk
+{
+ Eeze_Disk *disk;
+};
+
+/**
+ * @typedef Eeze_Event_Disk_Error
+ * @since 1.1
+ *
+ * Contains the human readable error message.
+ */
+typedef struct _Eeze_Event_Disk_Error Eeze_Event_Disk_Error;
+
+struct _Eeze_Event_Disk_Error
+{
+ Eeze_Disk *disk;
+ const char *message;
+};
+
+/**
+ * @brief Use this function to determine whether your eeze is disk-capable
+ *
+ * Since applications will die if they run/compile against a function that doesn't exist,
+ * if your application successfully runs/compiles with this function then you have eeze_disk.
+ * @since 1.1
+ */
+EAPI void eeze_disk_function(void);
+
+/**
+ * @brief Return whether mount support is available in eeze
+ *
+ * Use this function to determine whether your Eeze library was compiled with a mount
+ * binary available.
+ * @since 1.1
+ */
+EAPI Eina_Bool eeze_disk_can_mount(void);
+
+/**
+ * @brief Return whether unmount support is available in eeze
+ *
+ * Use this function to determine whether your Eeze library was compiled with an unmount
+ * binary available.
+ * @since 1.1
+ */
+EAPI Eina_Bool eeze_disk_can_unmount(void);
+
+/**
+ * @brief Return whether eject support is available in eeze
+ *
+ * Use this function to determine whether your Eeze library was compiled with an eject
+ * binary available.
+ * @since 1.1
+ */
+EAPI Eina_Bool eeze_disk_can_eject(void);
+
+/**
+ * @brief Create a new disk object from a /sys/ path or /dev/ path
+ * @param path The /sys/ or /dev path of the disk; CANNOT be @c NULL.
+ * @return The new disk object
+ *
+ * This function creates a new #Eeze_Disk from @p path. Note that this function
+ * does the minimal amount of work in order to save memory, and udev info about the disk
+ * is not retrieved in this call.
+ * @since 1.1
+ */
+EAPI Eeze_Disk *eeze_disk_new(const char *path);
+
+/**
+ * @brief Create a new disk object from a mount point
+ * @param mount_point The mount point of the disk; CANNOT be @c NULL
+ * @return The new disk object
+ *
+ * This function creates a new #Eeze_Disk from @p mount_point. Note that this function
+ * does the minimal amount of work in order to save memory, and udev info about the disk
+ * is not retrieved in this call. If the disk is not currently mounted, it must have an entry
+ * in /etc/fstab.
+ * @since 1.1
+ */
+EAPI Eeze_Disk *eeze_disk_new_from_mount(const char *mount_point);
+
+/**
+ * @brief Frees a disk object
+ * @param disk The disk object to free
+ *
+ * This call frees an #Eeze_Disk. Once freed, the disk can no longer be used.
+ * @since 1.1
+ */
+EAPI void eeze_disk_free(Eeze_Disk *disk);
+
+/**
+ * @brief Retrieve all disk information
+ * @param disk
+ *
+ * Use this function to retrieve all of a disk's information at once, then use
+ * a "get" function to retrieve the value. Data retrieved in this call is cached,
+ * meaning that subsequent calls will return immediately without performing any work.
+ * @since 1.1
+ */
+EAPI void eeze_disk_scan(Eeze_Disk *disk);
+
+/**
+ * @brief Associate data with a disk
+ * @param disk The disk
+ * @param data The data
+ *
+ * Data can be associated with @p disk with this function.
+ * @see eeze_disk_data_get
+ * @since 1.1
+ */
+EAPI void eeze_disk_data_set(Eeze_Disk *disk, void *data);
+
+/**
+ * @brief Retrieve data previously associated with a disk
+ * @param disk The disk
+ * @return The data
+ *
+ * Data that has been previously associated with @p disk
+ * is returned with this function.
+ * @see eeze_disk_data_set
+ * @since 1.1
+ */
+EAPI void *eeze_disk_data_get(Eeze_Disk *disk);
+
+/**
+ * @brief Return the /sys/ path of a disk
+ * @param disk The disk
+ * @return The /sys/ path
+ *
+ * This retrieves the /sys/ path that udev associates with @p disk.
+ * @since 1.1
+ */
+EAPI const char *eeze_disk_syspath_get(Eeze_Disk *disk);
+
+/**
+ * @brief Return the /dev/ path of a disk
+ * @param disk The disk
+ * @return The /dev/ path
+ *
+ * This retrieves the /dev/ path that udev has created a device node at for @p disk.
+ * @since 1.1
+ */
+EAPI const char *eeze_disk_devpath_get(Eeze_Disk *disk);
+
+/**
+ * @brief Return the filesystem of the disk (if known)
+ * @param disk The disk
+ * @return The filesystem type
+ *
+ * This retrieves the filesystem that the disk is using, or @c NULL if unknown.
+ * @since 1.1
+ */
+EAPI const char *eeze_disk_fstype_get(Eeze_Disk *disk);
+
+/**
+ * @brief Return the manufacturing vendor of the disk
+ * @param disk The disk
+ * @return The vendor
+ *
+ * This retrieves the vendor which manufactured the disk, or @c NULL if unknown.
+ * @since 1.1
+ */
+EAPI const char *eeze_disk_vendor_get(Eeze_Disk *disk);
+
+/**
+ * @brief Return the model of the disk
+ * @param disk The disk
+ * @return The model
+ *
+ * This retrieves the model of the disk, or @c NULL if unknown.
+ * @since 1.1
+ */
+EAPI const char *eeze_disk_model_get(Eeze_Disk *disk);
+
+/**
+ * @brief Return the serial number of the disk
+ * @param disk The disk
+ * @return The serial number
+ *
+ * This retrieves the serial number the disk, or @c NULL if unknown.
+ * @since 1.1
+ */
+EAPI const char *eeze_disk_serial_get(Eeze_Disk *disk);
+
+/**
+ * @brief Return the UUID of the disk
+ * @param disk The disk
+ * @return The UUID
+ *
+ * This retrieves the UUID of the disk, or @c NULL if unknown.
+ * A UUID is a 36 character (hopefully) unique identifier which can
+ * be used to store persistent information about a disk.
+ * @since 1.1
+ */
+EAPI const char *eeze_disk_uuid_get(Eeze_Disk *disk);
+
+/**
+ * @brief Return the label of the disk
+ * @param disk The disk
+ * @return The label
+ *
+ * This retrieves the label (name) of the disk, or @c NULL if unknown.
+ * @since 1.1
+ */
+EAPI const char *eeze_disk_label_get(Eeze_Disk *disk);
+
+/**
+ * @brief Return the #Eeze_Disk_Type of the disk
+ * @param disk The disk
+ * @return The type
+ *
+ * This retrieves the #Eeze_Disk_Type of the disk. This call is useful for determining
+ * the bus that the disk is connected through.
+ * @since 1.1
+ */
+EAPI Eeze_Disk_Type eeze_disk_type_get(Eeze_Disk *disk);
+
+/**
+ * @brief Return whether the disk is removable
+ * @param disk The disk
+ * @return @c EINA_TRUE if removable, @c EINA_FALSE otherwise.
+ * @since 1.1
+ */
+EAPI Eina_Bool eeze_disk_removable_get(Eeze_Disk *disk);
+
+
+/**
+ * @brief Return the mount state of a disk
+ * @param disk The disk
+ * @return The mount state
+ *
+ * This returns the mounted state of the disk. @c EINA_TRUE if mounted,
+ * @c EINA_FALSE otherwise.
+ * @since 1.1
+ */
+EAPI Eina_Bool eeze_disk_mounted_get(Eeze_Disk *disk);
+
+/**
+ * @brief Get the previously set mount wrapper for a disk
+ * @param disk The disk
+ * @return The wrapper, or @c NULL on failure.
+ *
+ * This returns the wrapper previously set with eeze_disk_mount_wrapper_set
+ * @since 1.1
+ */
+EAPI const char *eeze_disk_mount_wrapper_get(Eeze_Disk *disk);
+
+/**
+ * @brief Set a wrapper to run mount commands with
+ * @param disk The disk to wrap mount commands for
+ * @param wrapper The wrapper executable
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ *
+ * Use this function to set up a wrapper for running mount/umount commands. The wrapper must
+ * NOT use any of the standard mount/umount error code return values, and it must return 0 on success.
+ * Note that this function will call stat() on @p wrapper if not @c NULL to test for existence.
+ * @since 1.1
+ */
+EAPI Eina_Bool eeze_disk_mount_wrapper_set(Eeze_Disk *disk, const char *wrapper);
+
+/**
+ * @brief Begin a mount operation on the disk
+ * @param disk The disk
+ * @return @c EINA_TRUE if the operation was started, @c EINA_FALSE otherwise.
+ *
+ * This call is used to begin a mount operation on @p disk. The operation will
+ * run asynchronously in a pipe, emitting an EEZE_EVENT_DISK_MOUNT event with the disk object
+ * as its event on completion. If any errors are encountered, they will automatically logged
+ * to the eeze_disk domain and an EEZE_EVENT_DISK_ERROR event will be generated with an #Eeze_Event_Disk_Error
+ * struct as its event.
+ *
+ * NOTE: The return value of this function does not in any way reflect the mount state of a disk.
+ * @since 1.1
+ */
+EAPI Eina_Bool eeze_disk_mount(Eeze_Disk *disk);
+
+/**
+ * @brief Begin an unmount operation on the disk
+ * @param disk The disk
+ * @return @c EINA_TRUE if the operation was started, @c EINA_FALSE otherwise.
+ *
+ * This call is used to begin an unmount operation on @p disk. The operation will
+ * run asynchronously in a pipe, emitting an EEZE_EVENT_DISK_UNMOUNT event with the disk object
+ * as its event on completion. If any errors are encountered, they will automatically logged
+ * to the eeze_disk domain and an EEZE_EVENT_DISK_ERROR event will be generated with
+ * an #Eeze_Event_Disk_Error struct as its event.
+ *
+ * NOTE: The return value of this function does not in any way reflect the mount state of a disk.
+ * @since 1.1
+ */
+EAPI Eina_Bool eeze_disk_unmount(Eeze_Disk *disk);
+
+/**
+ * @brief Begin an eject operation on the disk
+ * @param disk The disk
+ * @return @c EINA_TRUE if the operation was started, @c EINA_FALSE otherwise.
+ *
+ * This call is used to begin an eject operation on @p disk. The operation will
+ * run asynchronously in a pipe, emitting an EEZE_EVENT_DISK_EJECT event with the disk object
+ * as its event on completion. If any errors are encountered, they will automatically logged
+ * to the eeze_disk domain and an EEZE_EVENT_DISK_ERROR event will be generated with
+ * an #Eeze_Event_Disk_Error struct as its event.
+ *
+ * NOTE: The return value of this function does not in any way reflect the mount state of a disk.
+ * @since 1.1
+ */
+EAPI Eina_Bool eeze_disk_eject(Eeze_Disk *disk);
+/**
+ * @brief Cancel a pending operation on the disk
+ * @param disk The disk
+ *
+ * This function cancels the current pending operation on @p disk which was previously
+ * started with eeze_disk_mount or eeze_disk_unmount.
+ * @since 1.1
+ */
+EAPI void eeze_disk_cancel(Eeze_Disk *disk);
+
+/**
+ * @brief Return the mount point of a disk
+ * @param disk The disk
+ * @return The mount point
+ *
+ * This function returns the mount point associated with @p disk.
+ * Note that to determine whether the disk is actually mounted, eeze_disk_mounted_get should be used.
+ * @since 1.1
+ */
+EAPI const char *eeze_disk_mount_point_get(Eeze_Disk *disk);
+
+/**
+ * @brief Set the mount point of a disk
+ * @param disk The disk
+ * @param mount_point The mount point
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ *
+ * This function sets the mount point associated with @p disk.
+ * Note that to determine whether the disk is actually mounted, eeze_disk_mounted_get should be used.
+ * Also note that this function cannot be used while the disk is mounted to avoid losing the current mount point.
+ * @since 1.1
+ */
+EAPI Eina_Bool eeze_disk_mount_point_set(Eeze_Disk *disk, const char *mount_point);
+
+/**
+ * @brief Set the mount options using flags
+ * @param disk The disk
+ * @param opts An ORed set of #Eeze_Mount_Opts
+ * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
+ *
+ * This function replaces the current mount opts of a disk with the ones in @p opts.
+ * @since 1.1
+ */
+EAPI Eina_Bool eeze_disk_mountopts_set(Eeze_Disk *disk, unsigned long opts);
+
+/**
+ * @brief Get the flags of a disk's current mount options
+ * @param disk The disk
+ * @return An ORed set of #Eeze_Mount_Opts, 0 on failure
+ *
+ * This function returns the current mount opts of a disk.
+ * @since 1.1
+ */
+EAPI unsigned long eeze_disk_mountopts_get(Eeze_Disk *disk);
+
+
+/**
+ * @brief Begin watching mtab and fstab
+ * @return @c EINA_TRUE if watching was started, @c EINA_FALSE otherwise.
+ *
+ * This function creates inotify watches on /etc/mtab and /etc/fstab and watches
+ * them for changes. This function should be used when expecting a lot of disk
+ * mounting/unmounting while you need disk data since it will automatically update
+ * certain necessary data instead of waiting.
+ * @see eeze_mount_mtab_scan, eeze_mount_fstab_scan
+ * @since 1.1
+ */
+EAPI Eina_Bool eeze_mount_tabs_watch(void);
+
+/**
+ * @brief Stop watching /etc/fstab and /etc/mtab
+ *
+ * This function stops watching fstab and mtab. Data obtained previously will be saved.
+ * @since 1.1
+ */
+EAPI void eeze_mount_tabs_unwatch(void);
+
+/**
+ * @brief Scan /etc/mtab a single time
+ * @return @c EINA_TRUE if mtab could be scanned, @c EINA_FALSE otherwise.
+ *
+ * This function is used to perform a single scan on /etc/mtab. It is used to gather
+ * information about mounted filesystems which can then be used with your #Eeze_Disk objects
+ * where appropriate. These files will automatically be scanned any time a mount point or mount state
+ * is requested unless eeze_mount_tabs_watch has been called previously, in which case data is stored for
+ * use.
+ * If this function is called after eeze_mount_tabs_watch, @c EINA_TRUE will be returned.
+ * @see eeze_mount_tabs_watch, eeze_mount_fstab_scan
+ * @since 1.1
+ */
+EAPI Eina_Bool eeze_mount_mtab_scan(void);
+
+/**
+ * @brief Scan /etc/fstab a single time
+ * @return @c EINA_TRUE if mtab could be scanned, @c EINA_FALSE otherwise.
+ *
+ * This function is used to perform a single scan on /etc/fstab. It is used to gather
+ * information about mounted filesystems which can then be used with your #Eeze_Disk objects
+ * where appropriate. These files will automatically be scanned any time a mount point or mount state
+ * is requested unless eeze_mount_tabs_watch has been called previously, in which case data is stored for
+ * use.
+ * If this function is called after eeze_mount_tabs_watch, @c EINA_TRUE will be returned.
+ * @see eeze_mount_tabs_watch, eeze_mount_mtab_scan
+ * @since 1.1
+ */
+EAPI Eina_Bool eeze_mount_fstab_scan(void);
+
+/**
+ * @brief Get the property value of a disk
+ *
+ * @param disk The disk
+ * @param property The property to get; full list of these is a FIXME
+ * @return A stringshared char* with the property or @c NULL on failure.
+ * @since 1.1
+ */
+
+EAPI const char *eeze_disk_udev_get_property(Eeze_Disk *disk, const char *property);
+
+/**
+ * @brief Get the sysattr value of a disk.
+ *
+ * @param disk The disk
+ * @param sysattr The sysattr to get; full list of these is a FIXME
+ * @return A stringshared char* with the sysattr or @c NULL on failure.
+ * @since 1.1
+ */
+
+EAPI const char *eeze_disk_udev_get_sysattr(Eeze_Disk *disk, const char *sysattr);
+
+/**
+ * Find the root device of a disk.
+ *
+ * @param disk The disk
+ * @return The syspath of the parent device
+ *
+ * Return a stringshared syspath (/sys/$syspath) for the parent device.
+ * @since 1.1
+ */
+EAPI const char *eeze_disk_udev_get_parent(Eeze_Disk *disk);
+
+/**
+ * Walks up the device chain using the device from @p disk,
+ * checking each device for @p sysattr with (optional) @p value.
+ *
+ * @param disk The disk to walk
+ * @param sysattr The attribute to find
+ * @param value OPTIONAL: The value that @p sysattr should have, or @c NULL.
+ *
+ * @return If the sysattr (with value) is found, returns @c EINA_TRUE,
+ * @c EINA_FALSE otherwise.
+ * @since 1.1
+ */
+EAPI Eina_Bool eeze_disk_udev_walk_check_sysattr(Eeze_Disk *disk, const char *sysattr, const char *value);
+
+/**
+ * @brief Walks up the device chain of @p disk
+ * checking each device for @p sysattr and returns the value if found.
+ *
+ * @param disk The disk
+ * @param sysattr The attribute to find
+ *
+ * @return The stringshared value of @p sysattr if found, or @c NULL.
+ * @since 1.1
+ */
+EAPI const char *eeze_disk_udev_walk_get_sysattr(Eeze_Disk *disk, const char *sysattr);
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @}
+ */
+#endif
diff --git a/src/lib/Eeze_Net.h b/src/lib/Eeze_Net.h
new file mode 100644
index 0000000..97a17ca
--- /dev/null
+++ b/src/lib/Eeze_Net.h
@@ -0,0 +1,62 @@
+#ifndef EEZE_NET_H
+#define EEZE_NET_H
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+#else
+# define EAPI
+#endif
+
+#include <Eina.h>
+#include <Ecore.h>
+
+/**
+ * @file Eeze_Net.h
+ * @brief Network manipulation
+ *
+ * Eeze net functions allow you to gather information about network objects
+ *
+ * @addtogroup net Net
+ * @{
+ */
+
+typedef struct Eeze_Net Eeze_Net;
+
+typedef enum
+{
+ EEZE_NET_ADDR_TYPE_IP,
+ EEZE_NET_ADDR_TYPE_IP6,
+ EEZE_NET_ADDR_TYPE_BROADCAST,
+ EEZE_NET_ADDR_TYPE_BROADCAST6,
+ EEZE_NET_ADDR_TYPE_NETMASK,
+ EEZE_NET_ADDR_TYPE_NETMASK6,
+} Eeze_Net_Addr_Type;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EAPI Eeze_Net *eeze_net_new(const char *name);
+EAPI void eeze_net_free(Eeze_Net *net);
+EAPI const char *eeze_net_mac_get(Eeze_Net *net);
+EAPI int eeze_net_idx_get(Eeze_Net *net);
+EAPI Eina_Bool eeze_net_scan(Eeze_Net *net);
+EAPI const char *eeze_net_addr_get(Eeze_Net *net, Eeze_Net_Addr_Type type);
+EAPI const char *eeze_net_attribute_get(Eeze_Net *net, const char *attr);
+EAPI const char *eeze_net_syspath_get(Eeze_Net *net);
+EAPI Eina_List *eeze_net_list(void);
+
+#ifdef __cplusplus
+}
+#endif
+/** @} */
+
+#endif
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
new file mode 100644
index 0000000..eb3a18f
--- /dev/null
+++ b/src/lib/Makefile.am
@@ -0,0 +1,39 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = @EEZE_CFLAGS@
+
+includes_HEADERS = Eeze.h Eeze_Net.h
+
+libeeze_la_SOURCES = \
+eeze_main.c \
+eeze_net.c \
+eeze_net_private.h \
+eeze_udev_find.c \
+eeze_udev_private.h \
+eeze_udev_private.c \
+eeze_udev_syspath.c \
+eeze_udev_walk.c \
+eeze_udev_watch.c
+
+if HAVE_EEZE_MOUNT
+ AM_CFLAGS = @EEZE_CFLAGS@ @LIBMOUNT_CFLAGS@ @ECORE_FILE_CFLAGS@
+ libeeze_la_SOURCES += eeze_disk.c eeze_disk_udev.c eeze_disk_mount.c eeze_disk_private.h
+if OLD_LIBMOUNT
+ libeeze_la_SOURCES += eeze_disk_libmount_old.c
+else
+ libeeze_la_SOURCES += eeze_disk_libmount.c
+endif
+ includes_HEADERS += Eeze_Disk.h
+else
+ AM_CFLAGS = @EEZE_CFLAGS@
+endif
+
+lib_LTLIBRARIES = libeeze.la
+includesdir = $(includedir)/eeze-@VMAJ@
+
+if HAVE_EEZE_MOUNT
+ libeeze_la_LIBADD = @EEZE_LIBS@ @LIBMOUNT_LIBS@ @ECORE_FILE_LIBS@
+else
+ libeeze_la_LIBADD = @EEZE_LIBS@
+endif
+libeeze_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
diff --git a/src/lib/eeze_disk.c b/src/lib/eeze_disk.c
new file mode 100644
index 0000000..8d1aeec
--- /dev/null
+++ b/src/lib/eeze_disk.c
@@ -0,0 +1,476 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <Ecore.h>
+#include <Eeze.h>
+#include <Eeze_Disk.h>
+
+#include "eeze_udev_private.h"
+#include "eeze_disk_private.h"
+
+int _eeze_disk_log_dom = -1;
+Eina_List *_eeze_disks = NULL;
+
+static Eeze_Disk_Type
+_eeze_disk_type_find(Eeze_Disk *disk)
+{
+ const char *test;
+ Eeze_Disk_Type ret;
+ Eina_Bool filesystem = EINA_FALSE; /* this will have no children */
+
+ if (udev_device_get_property_value(disk->device, "ID_CDROM"))
+ return EEZE_DISK_TYPE_CDROM;
+ test = udev_device_get_property_value(disk->device, "ID_FS_USAGE");
+ if ((!test) || strcmp(test, "filesystem"))
+ {
+ test = _walk_children_get_attr(disk->syspath, "ID_CDROM", "block", EINA_TRUE);
+ if (test)
+ {
+ eina_stringshare_del(test);
+ return EEZE_DISK_TYPE_CDROM;
+ }
+ }
+ else
+ filesystem = EINA_TRUE;
+ if (udev_device_get_property_value(disk->device, "ID_ATA"))
+ return EEZE_DISK_TYPE_INTERNAL;
+ if (!filesystem)
+ {
+ test = _walk_children_get_attr(disk->syspath, "ID_ATA", "block", EINA_TRUE);
+ if (test)
+ {
+ eina_stringshare_del(test);
+ return EEZE_DISK_TYPE_INTERNAL;
+ }
+ }
+ test = udev_device_get_property_value(disk->device, "ID_BUS");
+ if (test)
+ {
+ if (!strcmp(test, "ata")) return EEZE_DISK_TYPE_INTERNAL;
+ if (!strcmp(test, "usb")) return EEZE_DISK_TYPE_USB;
+ return EEZE_DISK_TYPE_UNKNOWN; /* FIXME */
+ }
+ if ((!test) && (!filesystem))
+ test = _walk_children_get_attr(disk->syspath, "ID_BUS", "block", EINA_TRUE);
+ if (!test)
+ {
+ _udev_device *dev;
+
+ for (dev = udev_device_get_parent(disk->device); dev; dev = udev_device_get_parent(dev))
+ {
+ test = udev_device_get_subsystem(dev);
+ if (!test) return EEZE_DISK_TYPE_UNKNOWN;
+ if (!strcmp(test, "block")) continue;
+ if (!strcmp(test, "mmc")) return EEZE_DISK_TYPE_FLASH;
+ break;
+ }
+ return EEZE_DISK_TYPE_UNKNOWN; /* FIXME */
+ }
+
+ if (!strcmp(test, "ata")) ret = EEZE_DISK_TYPE_INTERNAL;
+ else if (!strcmp(test, "usb")) ret = EEZE_DISK_TYPE_USB;
+ else ret = EEZE_DISK_TYPE_UNKNOWN; /* FIXME */
+
+ eina_stringshare_del(test);
+
+ return ret;
+}
+
+static _udev_device *
+_eeze_disk_device_from_property(const char *prop, Eina_Bool uuid)
+{
+ _udev_enumerate *en;
+ _udev_list_entry *devs, *cur;
+ _udev_device *device = NULL;
+ const char *devname;
+
+ en = udev_enumerate_new(udev);
+
+ if (!en)
+ return NULL;
+
+ if (uuid)
+ udev_enumerate_add_match_property(en, "ID_FS_UUID", prop);
+ else
+ udev_enumerate_add_match_property(en, "ID_FS_LABEL", prop);
+ udev_enumerate_scan_devices(en);
+ devs = udev_enumerate_get_list_entry(en);
+ udev_list_entry_foreach(cur, devs)
+ {
+ devname = udev_list_entry_get_name(cur);
+ device = udev_device_new_from_syspath(udev, devname);
+ break;
+ }
+ udev_enumerate_unref(en);
+ return device;
+
+}
+
+void
+eeze_disk_shutdown(void)
+{
+ eeze_mount_shutdown();
+ ecore_file_shutdown();
+ eina_log_domain_unregister(_eeze_disk_log_dom);
+ _eeze_disk_log_dom = -1;
+}
+
+Eina_Bool
+eeze_disk_init(void)
+{
+ _eeze_disk_log_dom = eina_log_domain_register("eeze_disk", EINA_COLOR_LIGHTBLUE);
+
+ if (_eeze_disk_log_dom < 0)
+ {
+ EINA_LOG_ERR("Could not register 'eeze_disk' log domain.");
+ goto disk_fail;
+ }
+
+ if (!ecore_file_init())
+ goto disk_fail;
+ if (!eeze_mount_init())
+ goto ecore_file_fail;
+
+ return EINA_TRUE;
+
+ecore_file_fail:
+ ecore_file_shutdown();
+disk_fail:
+ eina_log_domain_unregister(_eeze_disk_log_dom);
+ _eeze_disk_log_dom = -1;
+ return EINA_FALSE;
+}
+
+EAPI void
+eeze_disk_function(void)
+{
+}
+
+EAPI Eeze_Disk *
+eeze_disk_new(const char *path)
+{
+ Eeze_Disk *disk;
+ _udev_device *dev;
+ const char *syspath = NULL;
+ Eina_Bool is_dev = EINA_FALSE;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
+
+ if (!strncmp(path, "/dev/", 5))
+ {
+ is_dev = EINA_TRUE;
+ syspath = eeze_udev_devpath_get_syspath(path);
+ if (!syspath)
+ return NULL;
+
+ if (!(dev = _new_device(syspath)))
+ {
+ eina_stringshare_del(syspath);
+ return NULL;
+ }
+ }
+ else if (!(dev = _new_device(path)))
+ return NULL;
+
+
+ if (!(disk = calloc(1, sizeof(Eeze_Disk))))
+ return NULL;
+
+
+ if (is_dev)
+ {
+ disk->devpath = eina_stringshare_add(path);
+ disk->syspath = syspath;
+ }
+ else
+ disk->syspath = eina_stringshare_add(udev_device_get_syspath(dev));
+
+
+ disk->device = dev;
+ disk->mount_opts = EEZE_DISK_MOUNTOPT_DEFAULTS;
+ disk->mount_cmd_changed = EINA_TRUE;
+ disk->unmount_cmd_changed = EINA_TRUE;
+
+ _eeze_disks = eina_list_append(_eeze_disks, disk);
+
+ return disk;
+}
+
+EAPI Eeze_Disk *
+eeze_disk_new_from_mount(const char *mount_point)
+{
+ Eeze_Disk *disk = NULL;
+ _udev_device *dev = NULL;
+ const char *syspath = NULL, *source, *uuid = NULL, *label = NULL, *devpath = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(mount_point, NULL);
+
+ if (!(source = eeze_disk_libmount_mp_find_source(mount_point)))
+ return NULL;
+
+ if (source[4] == '=')
+ {
+ source += 5;
+ uuid = eina_stringshare_add(source);
+ dev = _eeze_disk_device_from_property(uuid, EINA_TRUE);
+ }
+ else if (source[5] == '=')
+ {
+ source += 6;
+ label = eina_stringshare_add(source);
+ dev = _eeze_disk_device_from_property(label, EINA_FALSE);
+ }
+ else
+ {
+ const char *spath;
+
+ devpath = eina_stringshare_add(source);
+ spath = eeze_udev_devpath_get_syspath(devpath);
+ dev = _new_device(spath);
+ eina_stringshare_del(spath);
+ }
+
+ if (!dev)
+ goto error;
+
+ if (!(disk = calloc(1, sizeof(Eeze_Disk))))
+ goto error;
+
+ disk->syspath = udev_device_get_syspath(dev);
+
+ disk->device = dev;
+ disk->mount_cmd_changed = EINA_TRUE;
+ disk->unmount_cmd_changed = EINA_TRUE;
+ if (uuid)
+ disk->cache.uuid = uuid;
+ else if (label)
+ disk->cache.label = label;
+ else
+ disk->devpath = devpath;
+ disk->mount_point = eina_stringshare_add(mount_point);
+
+ _eeze_disks = eina_list_append(_eeze_disks, disk);
+
+ return disk;
+error:
+ if (uuid)
+ eina_stringshare_del(uuid);
+ else if (label)
+ eina_stringshare_del(label);
+ else if (devpath)
+ eina_stringshare_del(devpath);
+ if (syspath)
+ eina_stringshare_del(syspath);
+ if (dev)
+ udev_device_unref(dev);
+ return NULL;
+}
+
+EAPI void
+eeze_disk_free(Eeze_Disk *disk)
+{
+ extern Eina_List *eeze_events;
+ EINA_SAFETY_ON_NULL_RETURN(disk);
+
+ udev_device_unref(disk->device);
+ if (disk->mount_cmd)
+ eina_strbuf_free(disk->mount_cmd);
+ if (disk->unmount_cmd)
+ eina_strbuf_free(disk->unmount_cmd);
+ if (disk->eject_cmd)
+ eina_strbuf_free(disk->eject_cmd);
+ if (disk->mounter) ecore_exe_kill(disk->mounter);
+ _eeze_disks = eina_list_remove(_eeze_disks, disk);
+ eeze_events = eina_list_remove(eeze_events, disk);
+ free(disk);
+}
+
+EAPI void
+eeze_disk_scan(Eeze_Disk *disk)
+{
+ const char *test;
+ EINA_SAFETY_ON_NULL_RETURN(disk);
+ /* never rescan; if these values change then something is seriously wrong */
+ if (disk->cache.filled) return;
+
+ if (!disk->cache.vendor)
+ disk->cache.vendor = udev_device_get_property_value(disk->device, "ID_VENDOR");
+ if (!disk->cache.vendor)
+ if (!disk->cache.vendor) disk->cache.vendor = udev_device_get_sysattr_value(disk->device, "vendor");
+ if (!disk->cache.model)
+ disk->cache.model = udev_device_get_property_value(disk->device, "ID_MODEL");
+ if (!disk->cache.model)
+ if (!disk->cache.model) disk->cache.model = udev_device_get_sysattr_value(disk->device, "model");
+ if (!disk->cache.serial)
+ disk->cache.serial = udev_device_get_property_value(disk->device, "ID_SERIAL_SHORT");
+ if (!disk->cache.uuid)
+ disk->cache.uuid = udev_device_get_property_value(disk->device, "ID_FS_UUID");
+ if (!disk->cache.type)
+ disk->cache.type = _eeze_disk_type_find(disk);
+ if (!disk->cache.label)
+ disk->cache.label = udev_device_get_property_value(disk->device, "ID_FS_LABEL");
+ test = udev_device_get_sysattr_value(disk->device, "removable");
+ if (test) disk->cache.removable = !!strtol(test, NULL, 10);
+ else
+ test = _walk_children_get_attr(disk->syspath, "removable", "block", EINA_FALSE);
+ if (test)
+ {
+ disk->cache.removable = !!strtol(test, NULL, 10);
+ eina_stringshare_del(test);
+ }
+
+ disk->cache.filled = EINA_TRUE;
+}
+
+EAPI void
+eeze_disk_data_set(Eeze_Disk *disk, void *data)
+{
+ EINA_SAFETY_ON_NULL_RETURN(disk);
+
+ disk->data = data;
+}
+
+EAPI void *
+eeze_disk_data_get(Eeze_Disk *disk)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL);
+
+ return disk->data;
+}
+
+EAPI const char *
+eeze_disk_syspath_get(Eeze_Disk *disk)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL);
+
+ return disk->syspath;
+}
+
+EAPI const char *
+eeze_disk_devpath_get(Eeze_Disk *disk)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL);
+
+ if (disk->devpath)
+ return disk->devpath;
+ disk->devpath = udev_device_get_devnode(disk->device);
+ return disk->devpath;
+}
+
+EAPI const char *
+eeze_disk_fstype_get(Eeze_Disk *disk)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL);
+
+ return disk->fstype;
+}
+
+EAPI const char *
+eeze_disk_vendor_get(Eeze_Disk *disk)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL);
+
+ if (disk->cache.vendor)
+ return disk->cache.vendor;
+
+ disk->cache.vendor = udev_device_get_property_value(disk->device, "ID_VENDOR");
+ if (!disk->cache.vendor) disk->cache.vendor = udev_device_get_sysattr_value(disk->device, "vendor");
+ return disk->cache.vendor;
+}
+
+EAPI const char *
+eeze_disk_model_get(Eeze_Disk *disk)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL);
+
+ if (disk->cache.model)
+ return disk->cache.model;
+
+ disk->cache.model = udev_device_get_property_value(disk->device, "ID_MODEL");
+ if (!disk->cache.model) disk->cache.model = udev_device_get_sysattr_value(disk->device, "model");
+ return disk->cache.model;
+}
+
+EAPI const char *
+eeze_disk_serial_get(Eeze_Disk *disk)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL);
+
+ if (disk->cache.serial)
+ return disk->cache.serial;
+ disk->cache.serial = udev_device_get_property_value(disk->device, "ID_SERIAL_SHORT");
+ return disk->cache.serial;
+}
+
+EAPI const char *
+eeze_disk_uuid_get(Eeze_Disk *disk)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL);
+
+ if (disk->cache.uuid)
+ return disk->cache.uuid;
+ disk->cache.uuid = udev_device_get_property_value(disk->device, "ID_FS_UUID");
+ return disk->cache.uuid;
+}
+
+EAPI const char *
+eeze_disk_label_get(Eeze_Disk *disk)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL);
+
+ if (disk->cache.label)
+ return disk->cache.label;
+ disk->cache.label = udev_device_get_property_value(disk->device, "ID_FS_LABEL");
+ return disk->cache.label;
+}
+
+EAPI Eeze_Disk_Type
+eeze_disk_type_get(Eeze_Disk *disk)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EEZE_DISK_TYPE_UNKNOWN);
+
+ if (disk->cache.type)
+ return disk->cache.type;
+ disk->cache.type = _eeze_disk_type_find(disk);
+ return disk->cache.type;
+}
+
+EAPI Eina_Bool
+eeze_disk_removable_get(Eeze_Disk *disk)
+{
+ const char *test;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE);
+
+ if (disk->cache.filled)
+ return disk->cache.removable;
+
+ test = udev_device_get_sysattr_value(disk->device, "removable");
+ if (test) disk->cache.removable = !!strtol(test, NULL, 10);
+ else
+ test = _walk_children_get_attr(disk->syspath, "removable", "block", EINA_FALSE);
+ if (test)
+ {
+ disk->cache.removable = !!strtol(test, NULL, 10);
+ eina_stringshare_del(test);
+ }
+ return disk->cache.removable;
+}
+
+EAPI Eina_Bool
+eeze_disk_can_mount(void)
+{
+ return MOUNTABLE;
+}
+
+EAPI Eina_Bool
+eeze_disk_can_unmount(void)
+{
+ return UNMOUNTABLE;
+}
+
+EAPI Eina_Bool
+eeze_disk_can_eject(void)
+{
+ return EJECTABLE;
+}
diff --git a/src/lib/eeze_disk_libmount.c b/src/lib/eeze_disk_libmount.c
new file mode 100644
index 0000000..d1c38e8
--- /dev/null
+++ b/src/lib/eeze_disk_libmount.c
@@ -0,0 +1,494 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef USE_UNSTABLE_LIBMOUNT_API
+# define USE_UNSTABLE_LIBMOUNT_API 1
+#endif
+
+#include <Ecore.h>
+#include <Eeze.h>
+#include <Eeze_Disk.h>
+#include <libmount.h>
+#include <unistd.h>
+
+#include "eeze_udev_private.h"
+#include "eeze_disk_private.h"
+
+/*
+ *
+ * PRIVATE
+ *
+ */
+
+static struct libmnt_optmap eeze_optmap[] =
+{
+ { "loop[=]", EEZE_DISK_MOUNTOPT_LOOP, 0 },
+ { "utf8", EEZE_DISK_MOUNTOPT_UTF8, 0 },
+ { "noexec", EEZE_DISK_MOUNTOPT_NOEXEC, 0 },
+ { "nosuid", EEZE_DISK_MOUNTOPT_NOSUID, 0 },
+ { "remount", EEZE_DISK_MOUNTOPT_REMOUNT, 0 },
+ { "uid[=]", EEZE_DISK_MOUNTOPT_UID, 0 },
+ { NULL, 0, 0 }
+};
+typedef struct libmnt_table libmnt_table;
+typedef struct libmnt_lock libmnt_lock;
+typedef struct libmnt_fs libmnt_fs;
+typedef struct libmnt_cache libmnt_cache;
+static Ecore_File_Monitor *_mtab_mon = NULL;
+static Ecore_File_Monitor *_fstab_mon = NULL;
+static Eina_Bool _watching = EINA_FALSE;
+static Eina_Bool _mtab_scan_active = EINA_FALSE;
+static Eina_Bool _mtab_locked = EINA_FALSE;
+static Eina_Bool _fstab_scan_active = EINA_FALSE;
+static libmnt_cache *_eeze_mount_mtab_cache = NULL;
+static libmnt_cache *_eeze_mount_fstab_cache = NULL;
+static libmnt_table *_eeze_mount_mtab = NULL;
+static libmnt_table *_eeze_mount_fstab = NULL;
+static libmnt_lock *_eeze_mtab_lock = NULL;
+extern Eina_List *_eeze_disks;
+
+static libmnt_table *_eeze_mount_tab_parse(const char *filename);
+static void _eeze_mount_tab_watcher(void *data, Ecore_File_Monitor *mon __UNUSED__, Ecore_File_Event event __UNUSED__, const char *path);
+
+static Eina_Bool
+_eeze_mount_lock_mtab(void)
+{
+// DBG("Locking mlock: %s", mnt_lock_get_linkfile(_eeze_mtab_lock));
+ if (EINA_LIKELY(access("/etc/mtab", W_OK)))
+ {
+ INF("Insufficient privs for mtab lock, continuing without lock");
+ return EINA_TRUE;
+ }
+ if (mnt_lock_file(_eeze_mtab_lock))
+ {
+ ERR("Couldn't lock mtab!");
+ return EINA_FALSE;
+ }
+ _mtab_locked = EINA_TRUE;
+ return EINA_TRUE;
+}
+
+static void
+_eeze_mount_unlock_mtab(void)
+{
+// DBG("Unlocking mlock: %s", mnt_lock_get_linkfile(_eeze_mtab_lock));
+ if (_mtab_locked) mnt_unlock_file(_eeze_mtab_lock);
+ _mtab_locked = EINA_FALSE;
+}
+
+
+static int
+_eeze_mount_tab_parse_errcb(libmnt_table *tab __UNUSED__, const char *filename, int line)
+{
+ ERR("%s:%d: could not parse line!", filename, line); /* most worthless error reporting ever. */
+ return -1;
+}
+
+/*
+ * I could use mnt_new_table_from_file() but this way gives much more detailed output
+ * on failure so why not
+ */
+static libmnt_table *
+_eeze_mount_tab_parse(const char *filename)
+{
+ libmnt_table *tab;
+
+ if (!(tab = mnt_new_table())) return NULL;
+ if (mnt_table_set_parser_errcb(tab, _eeze_mount_tab_parse_errcb))
+ {
+ ERR("Alloc!");
+ mnt_free_table(tab);
+ return NULL;
+ }
+
+ if (!mnt_table_parse_file(tab, filename))
+ return tab;
+
+ mnt_free_table(tab);
+ return NULL;
+}
+
+static void
+_eeze_mount_tab_watcher(void *data, Ecore_File_Monitor *mon __UNUSED__, Ecore_File_Event event __UNUSED__, const char *path)
+{
+ libmnt_table *bak;
+
+ if (
+ ((_mtab_scan_active) && (data)) || /* mtab has non-null data to avoid needing strcmp */
+ ((_fstab_scan_active) && (!data))
+ )
+ /* prevent scans from triggering a scan */
+ return;
+
+ bak = _eeze_mount_mtab;
+ if (data)
+ if (!_eeze_mount_lock_mtab())
+ { /* FIXME: maybe queue job here? */
+ ERR("Losing events...");
+ return;
+ }
+ _eeze_mount_mtab = _eeze_mount_tab_parse(path);
+ if (data)
+ _eeze_mount_unlock_mtab();
+ if (!_eeze_mount_mtab)
+ {
+ ERR("Could not parse %s! keeping old tab...", path);
+ goto error;
+ }
+ if (data)
+ {
+ Eina_List *l;
+ Eeze_Disk *disk;
+
+ /* catch externally initiated mounts on existing disks by comparing known mount state to current state */
+ EINA_LIST_FOREACH(_eeze_disks, l, disk)
+ {
+ Eina_Bool mounted;
+
+ mounted = disk->mounted;
+
+ if ((eeze_disk_libmount_mounted_get(disk) != mounted) && (!disk->mount_status))
+ {
+ if (!mounted)
+ {
+ Eeze_Event_Disk_Mount *e;
+ e = malloc(sizeof(Eeze_Event_Disk_Mount));
+ if (e)
+ {
+ e->disk = disk;
+ ecore_event_add(EEZE_EVENT_DISK_MOUNT, e, NULL, NULL);
+ }
+ }
+ else
+ {
+ Eeze_Event_Disk_Unmount *e;
+ e = malloc(sizeof(Eeze_Event_Disk_Unmount));
+ if (e)
+ {
+ e->disk = disk;
+ ecore_event_add(EEZE_EVENT_DISK_UNMOUNT, e, NULL, NULL);
+ }
+ }
+ }
+ }
+ }
+
+ mnt_free_table(bak);
+ if (data)
+ {
+ mnt_free_cache(_eeze_mount_mtab_cache);
+ _eeze_mount_mtab_cache = mnt_new_cache();
+ mnt_table_set_cache(_eeze_mount_mtab, _eeze_mount_mtab_cache);
+ }
+ else
+ {
+ mnt_free_cache(_eeze_mount_fstab_cache);
+ _eeze_mount_fstab_cache = mnt_new_cache();
+ mnt_table_set_cache(_eeze_mount_fstab, _eeze_mount_fstab_cache);
+ }
+ return;
+
+error:
+ mnt_free_table(_eeze_mount_mtab);
+ _eeze_mount_mtab = bak;
+}
+
+/*
+ *
+ * INVISIBLE
+ *
+ */
+
+Eina_Bool
+eeze_libmount_init(void)
+{
+ if (_eeze_mtab_lock)
+ return EINA_TRUE;
+ if (!(_eeze_mtab_lock = mnt_new_lock("/etc/mtab", 0)))
+ return EINA_FALSE;
+ return EINA_TRUE;
+}
+
+void
+eeze_libmount_shutdown(void)
+{
+ if (_eeze_mount_fstab)
+ {
+ mnt_free_table(_eeze_mount_fstab);
+ mnt_free_cache(_eeze_mount_fstab_cache);
+ }
+ if (_eeze_mount_mtab)
+ {
+ mnt_free_table(_eeze_mount_mtab);
+ mnt_free_cache(_eeze_mount_mtab_cache);
+ }
+ eeze_mount_tabs_unwatch();
+ if (!_eeze_mtab_lock)
+ return;
+
+ mnt_unlock_file(_eeze_mtab_lock);
+ mnt_free_lock(_eeze_mtab_lock);
+ _eeze_mtab_lock = NULL;
+}
+
+unsigned long
+eeze_disk_libmount_opts_get(Eeze_Disk *disk)
+{
+ libmnt_fs *mnt;
+ const char *opts;
+ unsigned long f = 0;
+
+ if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan())
+ return 0;
+
+ mnt = mnt_table_find_tag(_eeze_mount_mtab, "UUID", eeze_disk_uuid_get(disk), MNT_ITER_BACKWARD);
+ if (!mnt)
+ mnt = mnt_table_find_tag(_eeze_mount_fstab, "UUID", eeze_disk_uuid_get(disk), MNT_ITER_BACKWARD);
+
+ if (!mnt) return 0;
+
+ opts = mnt_fs_get_fs_options(mnt);
+ if (!opts) return 0;
+ if (!mnt_optstr_get_flags(opts, &f, eeze_optmap)) return 0;
+ return f;
+}
+
+/*
+ * helper function to return whether a disk is mounted
+ */
+Eina_Bool
+eeze_disk_libmount_mounted_get(Eeze_Disk *disk)
+{
+ libmnt_fs *mnt;
+
+ if (!disk)
+ return EINA_FALSE;
+
+ if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan())
+ return EINA_FALSE;
+
+ mnt = mnt_table_find_srcpath(_eeze_mount_mtab, eeze_disk_devpath_get(disk), MNT_ITER_BACKWARD);
+ if (!mnt)
+ {
+ disk->mounted = EINA_FALSE;
+ return EINA_FALSE;
+ }
+
+ eina_stringshare_replace(&disk->mount_point, mnt_fs_get_target(mnt));
+ disk->mounted = EINA_TRUE;
+ return EINA_TRUE;
+}
+
+
+/*
+ * helper function to return the device that is mounted at a mount point
+ */
+const char *
+eeze_disk_libmount_mp_find_source(const char *mount_point)
+{
+ libmnt_fs *mnt;
+
+ if (!mount_point)
+ return NULL;
+
+ if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan())
+ return NULL;
+
+ mnt = mnt_table_find_target(_eeze_mount_mtab, mount_point, MNT_ITER_BACKWARD);
+ if (!mnt)
+ mnt = mnt_table_find_target(_eeze_mount_fstab, mount_point, MNT_ITER_BACKWARD);
+
+ if (!mnt)
+ return NULL;
+
+ return mnt_fs_get_source(mnt);
+}
+
+/*
+ * helper function to return a mount point from a uuid
+ */
+const char *
+eeze_disk_libmount_mp_lookup_by_uuid(const char *uuid)
+{
+ libmnt_fs *mnt;
+
+ if (!uuid)
+ return NULL;
+
+ if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan())
+ return NULL;
+
+ mnt = mnt_table_find_tag(_eeze_mount_fstab, "UUID", uuid, MNT_ITER_BACKWARD);
+
+ if (!mnt)
+ return NULL;
+
+ return mnt_fs_get_target(mnt);
+}
+
+/*
+ * helper function to return a mount point from a label
+ */
+const char *
+eeze_disk_libmount_mp_lookup_by_label(const char *label)
+{
+ libmnt_fs *mnt;
+
+ if (!label)
+ return NULL;
+
+ if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan())
+ return NULL;
+
+ mnt = mnt_table_find_tag(_eeze_mount_fstab, "LABEL", label, MNT_ITER_BACKWARD);
+
+ if (!mnt)
+ return NULL;
+
+ return mnt_fs_get_target(mnt);
+}
+
+/*
+ * helper function to return a mount point from a /dev/ path
+ */
+const char *
+eeze_disk_libmount_mp_lookup_by_devpath(const char *devpath)
+{
+ libmnt_fs *mnt;
+
+ if (!devpath)
+ return NULL;
+
+ if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan())
+ return NULL;
+
+ mnt = mnt_table_find_srcpath(_eeze_mount_mtab, devpath, MNT_ITER_BACKWARD);
+ if (!mnt)
+ mnt = mnt_table_find_srcpath(_eeze_mount_fstab, devpath, MNT_ITER_BACKWARD);
+
+ if (!mnt)
+ return NULL;
+
+ return mnt_fs_get_target(mnt);
+}
+
+/*
+ *
+ * API
+ *
+ */
+
+EAPI Eina_Bool
+eeze_mount_tabs_watch(void)
+{
+ libmnt_table *bak;
+
+ if (_watching)
+ return EINA_TRUE;
+
+ if (!_eeze_mount_lock_mtab())
+ return EINA_FALSE;
+
+ bak = _eeze_mount_tab_parse("/etc/mtab");
+ _eeze_mount_unlock_mtab();
+ if (!bak)
+ goto error;
+
+ mnt_free_table(_eeze_mount_mtab);
+ _eeze_mount_mtab = bak;
+ if (!(bak = _eeze_mount_tab_parse("/etc/fstab")))
+ goto error;
+
+ mnt_free_table(_eeze_mount_fstab);
+ _eeze_mount_fstab = bak;
+
+ _eeze_mount_mtab_cache = mnt_new_cache();
+ mnt_table_set_cache(_eeze_mount_mtab, _eeze_mount_mtab_cache);
+
+ _eeze_mount_fstab_cache = mnt_new_cache();
+ mnt_table_set_cache(_eeze_mount_fstab, _eeze_mount_fstab_cache);
+
+ _mtab_mon = ecore_file_monitor_add("/etc/mtab", _eeze_mount_tab_watcher, (void*)1);
+ _fstab_mon = ecore_file_monitor_add("/etc/fstab", _eeze_mount_tab_watcher, NULL);
+ _watching = EINA_TRUE;
+
+ return EINA_TRUE;
+
+error:
+ if (!_eeze_mount_mtab)
+ ERR("Could not parse /etc/mtab!");
+ else
+ {
+ ERR("Could not parse /etc/fstab!");
+ mnt_free_table(_eeze_mount_mtab);
+ }
+ return EINA_FALSE;
+}
+
+EAPI void
+eeze_mount_tabs_unwatch(void)
+{
+ if (!_watching)
+ return;
+
+ ecore_file_monitor_del(_mtab_mon);
+ _mtab_mon = NULL;
+ ecore_file_monitor_del(_fstab_mon);
+ _fstab_mon = NULL;
+ _watching = EINA_FALSE;
+}
+
+EAPI Eina_Bool
+eeze_mount_mtab_scan(void)
+{
+ libmnt_table *bak;
+
+ if (_watching)
+ return EINA_TRUE;
+
+ if (!_eeze_mount_lock_mtab())
+ return EINA_FALSE;
+ bak = _eeze_mount_tab_parse("/etc/mtab");
+ _eeze_mount_unlock_mtab();
+ if (!bak)
+ goto error;
+ if (_eeze_mount_mtab)
+ {
+ mnt_free_table(_eeze_mount_mtab);
+ mnt_free_cache(_eeze_mount_mtab_cache);
+ }
+ _eeze_mount_mtab = bak;
+ _eeze_mount_mtab_cache = mnt_new_cache();
+ mnt_table_set_cache(_eeze_mount_mtab, _eeze_mount_mtab_cache);
+
+ return EINA_TRUE;
+
+error:
+ return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+eeze_mount_fstab_scan(void)
+{
+ libmnt_table *bak;
+ if (_watching)
+ return EINA_TRUE;
+
+ bak = _eeze_mount_tab_parse("/etc/fstab");
+ if (!bak)
+ goto error;
+ if (_eeze_mount_fstab)
+ {
+ mnt_free_table(_eeze_mount_fstab);
+ mnt_free_cache(_eeze_mount_fstab_cache);
+ }
+ _eeze_mount_fstab = bak;
+ _eeze_mount_fstab_cache = mnt_new_cache();
+ mnt_table_set_cache(_eeze_mount_fstab, _eeze_mount_fstab_cache);
+
+ return EINA_TRUE;
+
+error:
+ return EINA_FALSE;
+}
diff --git a/src/lib/eeze_disk_libmount_old.c b/src/lib/eeze_disk_libmount_old.c
new file mode 100644
index 0000000..20df62e
--- /dev/null
+++ b/src/lib/eeze_disk_libmount_old.c
@@ -0,0 +1,401 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef USE_UNSTABLE_LIBMOUNT_API
+# define USE_UNSTABLE_LIBMOUNT_API 1
+#endif
+
+#include <Ecore.h>
+#include <Eeze.h>
+#include <Eeze_Disk.h>
+#include <mount/mount.h>
+
+#include "eeze_udev_private.h"
+#include "eeze_disk_private.h"
+/*
+ *
+ * PRIVATE
+ *
+ */
+static Ecore_File_Monitor *_mtab_mon = NULL;
+static Ecore_File_Monitor *_fstab_mon = NULL;
+static Eina_Bool _watching = EINA_FALSE;
+static Eina_Bool _mtab_scan_active = EINA_FALSE;
+static Eina_Bool _fstab_scan_active = EINA_FALSE;
+static mnt_tab *_eeze_mount_mtab = NULL;
+static mnt_tab *_eeze_mount_fstab = NULL;
+static mnt_lock *_eeze_mtab_lock = NULL;
+extern Eina_List *_eeze_disks;
+
+static mnt_tab *_eeze_mount_tab_parse(const char *filename);
+static void _eeze_mount_tab_watcher(void *data, Ecore_File_Monitor *mon __UNUSED__, Ecore_File_Event event __UNUSED__, const char *path);
+
+static Eina_Bool
+_eeze_mount_lock_mtab(void)
+{
+ DBG("Locking mlock: %s", mnt_lock_get_linkfile(_eeze_mtab_lock));
+#if 0
+#warning this code is broken with current libmount!
+ if (mnt_lock_file(_eeze_mtab_lock))
+ {
+ ERR("Couldn't lock mtab!");
+ return EINA_FALSE;
+ }
+#endif
+ return EINA_TRUE;
+}
+
+static void
+_eeze_mount_unlock_mtab(void)
+{
+ DBG("Unlocking mlock: %s", mnt_lock_get_linkfile(_eeze_mtab_lock));
+ mnt_unlock_file(_eeze_mtab_lock);
+}
+
+/*
+ * I could use mnt_new_tab_from_file() but this way gives much more detailed output
+ * on failure so why not
+ */
+static mnt_tab *
+_eeze_mount_tab_parse(const char *filename)
+{
+ mnt_tab *tab;
+
+ if (!(tab = mnt_new_tab(filename)))
+ return NULL;
+ if (!mnt_tab_parse_file(tab))
+ return tab;
+
+ if (mnt_tab_get_nerrs(tab))
+ { /* parse error */
+ char buf[1024];
+
+ mnt_tab_strerror(tab, buf, sizeof(buf));
+ ERR("%s", buf);
+ }
+ else
+ /* system error */
+ ERR("%s", mnt_tab_get_name(tab));
+ mnt_free_tab(tab);
+ return NULL;
+}
+
+static void
+_eeze_mount_tab_watcher(void *data, Ecore_File_Monitor *mon __UNUSED__, Ecore_File_Event event __UNUSED__, const char *path)
+{
+ mnt_tab *bak;
+
+ if (
+ ((_mtab_scan_active) && (data)) || /* mtab has non-null data to avoid needing strcmp */
+ ((_fstab_scan_active) && (!data))
+ )
+ /* prevent scans from triggering a scan */
+ return;
+
+ bak = _eeze_mount_mtab;
+ if (data)
+ if (!_eeze_mount_lock_mtab())
+ { /* FIXME: maybe queue job here? */
+ ERR("Losing events...");
+ return;
+ }
+ _eeze_mount_mtab = _eeze_mount_tab_parse(path);
+ if (data)
+ _eeze_mount_unlock_mtab();
+ if (!_eeze_mount_mtab)
+ {
+ ERR("Could not parse %s! keeping old tab...", path);
+ goto error;
+ }
+
+ if (data)
+ {
+ Eina_List *l;
+ Eeze_Disk *disk;
+
+ /* catch externally initiated mounts on existing disks by comparing known mount state to current state */
+ EINA_LIST_FOREACH(_eeze_disks, l, disk)
+ {
+ Eina_Bool mounted;
+
+ mounted = disk->mounted;
+
+ if ((eeze_disk_libmount_mounted_get(disk) != mounted) && (!disk->mount_status))
+ {
+ if (!mounted)
+ {
+ Eeze_Event_Disk_Mount *e;
+ e = malloc(sizeof(Eeze_Event_Disk_Mount));
+ if (e)
+ {
+ e->disk = disk;
+ ecore_event_add(EEZE_EVENT_DISK_MOUNT, e, NULL, NULL);
+ }
+ }
+ else
+ {
+ Eeze_Event_Disk_Unmount *e;
+ e = malloc(sizeof(Eeze_Event_Disk_Unmount));
+ if (e)
+ {
+ e->disk = disk;
+ ecore_event_add(EEZE_EVENT_DISK_UNMOUNT, e, NULL, NULL);
+ }
+ }
+ }
+ }
+ }
+
+ mnt_free_tab(bak);
+ return;
+
+error:
+ mnt_free_tab(_eeze_mount_mtab);
+ _eeze_mount_mtab = bak;
+}
+
+/*
+ *
+ * INVISIBLE
+ *
+ */
+
+Eina_Bool
+eeze_libmount_init(void)
+{
+ if (_eeze_mtab_lock)
+ return EINA_TRUE;
+ if (!(_eeze_mtab_lock = mnt_new_lock(NULL, 0)))
+ return EINA_FALSE;
+ return EINA_TRUE;
+}
+
+void
+eeze_libmount_shutdown(void)
+{
+ if (!_eeze_mtab_lock)
+ return;
+
+ mnt_unlock_file(_eeze_mtab_lock);
+ mnt_free_lock(_eeze_mtab_lock);
+ _eeze_mtab_lock = NULL;
+}
+
+/*
+ * helper function to return whether a disk is mounted
+ */
+Eina_Bool
+eeze_disk_libmount_mounted_get(Eeze_Disk *disk)
+{
+ mnt_fs *mnt;
+
+ if (!disk)
+ return EINA_FALSE;
+
+ if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan())
+ return EINA_FALSE;
+
+ mnt = mnt_tab_find_srcpath(_eeze_mount_mtab, eeze_disk_devpath_get(disk), MNT_ITER_BACKWARD);
+ if (!mnt)
+ {
+ disk->mounted = EINA_FALSE;
+ return EINA_FALSE;
+ }
+
+ disk->mount_point = eina_stringshare_add(mnt_fs_get_target(mnt));
+ disk->mounted = EINA_TRUE;
+ return EINA_TRUE;
+}
+
+
+/*
+ * helper function to return the device that is mounted at a mount point
+ */
+const char *
+eeze_disk_libmount_mp_find_source(const char *mount_point)
+{
+ mnt_fs *mnt;
+
+ if (!mount_point)
+ return NULL;
+
+ if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan())
+ return NULL;
+
+ mnt = mnt_tab_find_target(_eeze_mount_mtab, mount_point, MNT_ITER_BACKWARD);
+ if (!mnt)
+ mnt = mnt_tab_find_target(_eeze_mount_fstab, mount_point, MNT_ITER_BACKWARD);
+
+ if (!mnt)
+ return NULL;
+
+ return mnt_fs_get_source(mnt);
+}
+
+/*
+ * helper function to return a mount point from a uuid
+ */
+const char *
+eeze_disk_libmount_mp_lookup_by_uuid(const char *uuid)
+{
+ mnt_fs *mnt;
+
+ if (!uuid)
+ return NULL;
+
+ if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan())
+ return NULL;
+
+ mnt = mnt_tab_find_tag(_eeze_mount_fstab, "UUID", uuid, MNT_ITER_BACKWARD);
+
+ if (!mnt)
+ return NULL;
+
+ return mnt_fs_get_target(mnt);
+}
+
+/*
+ * helper function to return a mount point from a label
+ */
+const char *
+eeze_disk_libmount_mp_lookup_by_label(const char *label)
+{
+ mnt_fs *mnt;
+
+ if (!label)
+ return NULL;
+
+ if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan())
+ return NULL;
+
+ mnt = mnt_tab_find_tag(_eeze_mount_fstab, "LABEL", label, MNT_ITER_BACKWARD);
+
+ if (!mnt)
+ return NULL;
+
+ return mnt_fs_get_target(mnt);
+}
+
+/*
+ * helper function to return a mount point from a /dev/ path
+ */
+const char *
+eeze_disk_libmount_mp_lookup_by_devpath(const char *devpath)
+{
+ mnt_fs *mnt;
+
+ if (!devpath)
+ return NULL;
+
+ if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan())
+ return NULL;
+
+ mnt = mnt_tab_find_srcpath(_eeze_mount_mtab, devpath, MNT_ITER_BACKWARD);
+ if (!mnt)
+ mnt = mnt_tab_find_srcpath(_eeze_mount_fstab, devpath, MNT_ITER_BACKWARD);
+
+ if (!mnt)
+ return NULL;
+
+ return mnt_fs_get_target(mnt);
+}
+
+/*
+ *
+ * API
+ *
+ */
+EAPI Eina_Bool
+eeze_mount_tabs_watch(void)
+{
+ mnt_tab *bak;
+
+ if (_watching)
+ return EINA_TRUE;
+
+ if (!_eeze_mount_lock_mtab())
+ return EINA_FALSE;
+
+ bak = _eeze_mount_tab_parse("/etc/mtab");
+ _eeze_mount_unlock_mtab();
+ if (!bak)
+ goto error;
+
+ mnt_free_tab(_eeze_mount_mtab);
+ _eeze_mount_mtab = bak;
+ if (!(bak = _eeze_mount_tab_parse("/etc/fstab")))
+ goto error;
+
+ mnt_free_tab(_eeze_mount_fstab);
+ _eeze_mount_fstab = bak;
+
+ _mtab_mon = ecore_file_monitor_add("/etc/mtab", _eeze_mount_tab_watcher, (void*)1);
+ _fstab_mon = ecore_file_monitor_add("/etc/fstab", _eeze_mount_tab_watcher, NULL);
+ _watching = EINA_TRUE;
+
+ return EINA_TRUE;
+
+error:
+ if (!_eeze_mount_mtab)
+ ERR("Could not parse /etc/mtab!");
+ else
+ {
+ ERR("Could not parse /etc/fstab!");
+ mnt_free_tab(_eeze_mount_mtab);
+ }
+ return EINA_FALSE;
+}
+
+EAPI void
+eeze_mount_tabs_unwatch(void)
+{
+ if (!_watching)
+ return;
+
+ ecore_file_monitor_del(_mtab_mon);
+ ecore_file_monitor_del(_fstab_mon);
+}
+
+EAPI Eina_Bool
+eeze_mount_mtab_scan(void)
+{
+ mnt_tab *bak;
+
+ if (_watching)
+ return EINA_TRUE;
+
+ if (!_eeze_mount_lock_mtab())
+ return EINA_FALSE;
+ bak = _eeze_mount_tab_parse("/etc/mtab");
+ _eeze_mount_unlock_mtab();
+ if (!bak)
+ goto error;
+ if (_eeze_mount_mtab)
+ mnt_free_tab(_eeze_mount_mtab);
+ _eeze_mount_mtab = bak;
+ return EINA_TRUE;
+
+error:
+ return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+eeze_mount_fstab_scan(void)
+{
+ mnt_tab *bak;
+ if (_watching)
+ return EINA_TRUE;
+
+ bak = _eeze_mount_tab_parse("/etc/fstab");
+ if (!bak)
+ goto error;
+ if (_eeze_mount_fstab)
+ mnt_free_tab(_eeze_mount_fstab);
+ _eeze_mount_fstab = bak;
+
+ return EINA_TRUE;
+
+error:
+ return EINA_FALSE;
+}
diff --git a/src/lib/eeze_disk_mount.c b/src/lib/eeze_disk_mount.c
new file mode 100644
index 0000000..5de67fb
--- /dev/null
+++ b/src/lib/eeze_disk_mount.c
@@ -0,0 +1,460 @@
+#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)
+ {
+ 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:
+ 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);
+ 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:
+ 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);
+ 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 *label;
+
+ label = eeze_disk_label_get(disk);
+ if (label)
+ {
+ mp = eeze_disk_libmount_mp_lookup_by_label(label);
+ eina_stringshare_del(label);
+ }
+ 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_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", strerror(errno));
+ return EINA_FALSE;
+ }
+ }
+ 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", disk->mount_point);
+ 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;
+}
diff --git a/src/lib/eeze_disk_private.h b/src/lib/eeze_disk_private.h
new file mode 100644
index 0000000..afe2172
--- /dev/null
+++ b/src/lib/eeze_disk_private.h
@@ -0,0 +1,92 @@
+#ifndef EEZE_DISK_PRIVATE_H
+#define EEZE_DISK_PRIVATE_H
+#include <Eeze.h>
+#include <Ecore_File.h>
+
+#ifndef EEZE_DISK_COLOR_DEFAULT
+#define EEZE_DISK_COLOR_DEFAULT EINA_COLOR_LIGHTBLUE
+#endif
+extern int _eeze_disk_log_dom;
+#ifdef CRI
+#undef CRI
+#endif
+
+#ifdef ERR
+#undef ERR
+#endif
+#ifdef INF
+#undef INF
+#endif
+#ifdef WARN
+#undef WARN
+#endif
+#ifdef DBG
+#undef DBG
+#endif
+
+#define CRI(...) EINA_LOG_DOM_CRIT(_eeze_disk_log_dom, __VA_ARGS__)
+#define DBG(...) EINA_LOG_DOM_DBG(_eeze_disk_log_dom, __VA_ARGS__)
+#define INF(...) EINA_LOG_DOM_INFO(_eeze_disk_log_dom, __VA_ARGS__)
+#define WARN(...) EINA_LOG_DOM_WARN(_eeze_disk_log_dom, __VA_ARGS__)
+#define ERR(...) EINA_LOG_DOM_ERR(_eeze_disk_log_dom, __VA_ARGS__)
+
+typedef enum
+{
+ EEZE_DISK_NULL = 0,
+ EEZE_DISK_MOUNTING = 1,
+ EEZE_DISK_UNMOUNTING = 2,
+ EEZE_DISK_EJECTING = 4
+} Eeze_Disk_Status;
+
+struct _Eeze_Disk
+{
+ _udev_device *device;
+ void *data;
+
+ int mount_status;
+ Eina_Strbuf *mount_cmd;
+ Eina_Strbuf *unmount_cmd;
+ Eina_Strbuf *eject_cmd;
+ Eina_Bool mount_cmd_changed : 1;
+ Eina_Bool unmount_cmd_changed : 1;
+ Eina_Bool mounted : 1;
+ Ecore_Exe *mounter;
+
+ const char *syspath;
+ const char *devpath;
+ const char *fstype;
+ const char *mount_point;
+ const char *mount_wrapper;
+ unsigned long mount_opts;
+ uid_t uid;
+
+ struct
+ {
+ Eeze_Disk_Type type;
+ Eina_Bool removable : 1;
+ const char *vendor;
+ const char *model;
+ const char *serial;
+ const char *uuid;
+ const char *label;
+ Eina_Bool filled : 1;
+ } cache;
+};
+
+Eina_Bool eeze_disk_init(void);
+void eeze_disk_shutdown(void);
+
+Eina_Bool eeze_mount_init(void);
+void eeze_mount_shutdown(void);
+
+Eina_Bool eeze_libmount_init(void);
+void eeze_libmount_shutdown(void);
+Eina_Bool eeze_disk_libmount_mounted_get(Eeze_Disk *disk);
+unsigned long eeze_disk_libmount_opts_get(Eeze_Disk *disk);
+const char *eeze_disk_libmount_mp_find_source(const char *mount_point);
+
+const char *eeze_disk_libmount_mp_lookup_by_uuid(const char *uuid);
+const char *eeze_disk_libmount_mp_lookup_by_label(const char *label);
+const char *eeze_disk_libmount_mp_lookup_by_devpath(const char *devpath);
+
+#endif
diff --git a/src/lib/eeze_disk_udev.c b/src/lib/eeze_disk_udev.c
new file mode 100644
index 0000000..ef7b160
--- /dev/null
+++ b/src/lib/eeze_disk_udev.c
@@ -0,0 +1,90 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <Ecore.h>
+#include <Eeze.h>
+#include <Eeze_Disk.h>
+
+#include "eeze_udev_private.h"
+#include "eeze_disk_private.h"
+
+EAPI const char *
+eeze_disk_udev_get_property(Eeze_Disk *disk, const char *property)
+{
+ const char *ret;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(property, NULL);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(!*property, NULL);
+
+ ret = udev_device_get_property_value(disk->device, property);
+ return eina_stringshare_add(ret);
+}
+
+EAPI const char *
+eeze_disk_udev_get_sysattr(Eeze_Disk *disk, const char *sysattr)
+{
+ const char *ret;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(sysattr, NULL);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(!*sysattr, NULL);
+
+ ret = udev_device_get_sysattr_value(disk->device, sysattr);
+ return eina_stringshare_add(ret);
+}
+
+EAPI const char *
+eeze_disk_udev_get_parent(Eeze_Disk *disk)
+{
+ _udev_device *parent;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL);
+
+ parent = udev_device_get_parent(disk->device);
+ return eina_stringshare_add(udev_device_get_syspath(parent));
+}
+
+EAPI Eina_Bool
+eeze_disk_udev_walk_check_sysattr(Eeze_Disk *disk,
+ const char *sysattr,
+ const char *value)
+{
+ _udev_device *child, *parent;
+ const char *test = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(sysattr, EINA_FALSE);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(!*sysattr, EINA_FALSE);
+
+ for (parent = disk->device; parent;
+ child = parent, parent = udev_device_get_parent(child))
+ {
+ if (!(test = udev_device_get_sysattr_value(parent, sysattr)))
+ continue;
+ if ((value && (!strcmp(test, value))) || (!value))
+ {
+ return EINA_TRUE;
+ break;
+ }
+ }
+ return EINA_FALSE;
+}
+
+EAPI const char *
+eeze_disk_udev_walk_get_sysattr(Eeze_Disk *disk,
+ const char *sysattr)
+{
+ _udev_device *child, *parent;
+ const char *test = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(sysattr, NULL);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(!*sysattr, NULL);
+
+ for (parent = disk->device; parent;
+ child = parent, parent = udev_device_get_parent(child))
+ {
+ test = udev_device_get_sysattr_value(parent, sysattr);
+ if (test) return eina_stringshare_add(test);
+ }
+ return EINA_FALSE;
+}
diff --git a/src/lib/eeze_main.c b/src/lib/eeze_main.c
new file mode 100644
index 0000000..b9954cf
--- /dev/null
+++ b/src/lib/eeze_main.c
@@ -0,0 +1,104 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <Ecore.h>
+#include <Eeze.h>
+#include <Eeze_Disk.h>
+#include "eeze_udev_private.h"
+#include "eeze_net_private.h"
+#include "eeze_disk_private.h"
+
+_udev *udev;
+
+int _eeze_udev_log_dom = -1;
+int _eeze_net_log_dom = -1;
+int _eeze_init_count = 0;
+
+static Eeze_Version _version = { VMAJ, VMIN, VMIC, VREV };
+EAPI Eeze_Version *eeze_version = &_version;
+
+EAPI int
+eeze_init(void)
+{
+ if (++_eeze_init_count != 1)
+ return _eeze_init_count;
+
+ if (!eina_init())
+ return 0;
+
+ _eeze_udev_log_dom = eina_log_domain_register("eeze_udev", EINA_COLOR_CYAN);
+ if (_eeze_udev_log_dom < 0)
+ {
+ EINA_LOG_ERR("Could not register 'eeze_udev' log domain.");
+ goto eina_fail;
+ }
+ _eeze_net_log_dom = eina_log_domain_register("eeze_net", EINA_COLOR_GREEN);
+ if (_eeze_net_log_dom < 0)
+ {
+ EINA_LOG_ERR("Could not register 'eeze_net' log domain.");
+ goto eina_net_fail;
+ }
+
+
+ if (!ecore_init())
+ goto ecore_fail;
+#ifdef HAVE_EEZE_MOUNT
+ if (!eeze_disk_init())
+ goto eeze_fail;
+#endif
+ if (!(udev = udev_new()))
+ {
+ EINA_LOG_ERR("Could not initialize udev library!");
+ goto fail;
+ }
+ if (!eeze_net_init())
+ {
+ EINA_LOG_ERR("Error initializing eeze_net subsystems!");
+ goto net_fail;
+ }
+
+ return _eeze_init_count;
+
+net_fail:
+ udev_unref(udev);
+fail:
+#ifdef HAVE_EEZE_MOUNT
+ eeze_disk_shutdown();
+eeze_fail:
+#endif
+ ecore_shutdown();
+ecore_fail:
+ eina_log_domain_unregister(_eeze_net_log_dom);
+ _eeze_net_log_dom = -1;
+eina_net_fail:
+ eina_log_domain_unregister(_eeze_udev_log_dom);
+ _eeze_udev_log_dom = -1;
+eina_fail:
+ eina_shutdown();
+ return 0;
+}
+
+EAPI int
+eeze_shutdown(void)
+{
+ if (_eeze_init_count <= 0)
+ {
+ EINA_LOG_ERR("Init count not greater than 0 in shutdown.");
+ return 0;
+ }
+ if (--_eeze_init_count != 0)
+ return _eeze_init_count;
+
+ udev_unref(udev);
+#ifdef HAVE_EEZE_MOUNT
+ eeze_disk_shutdown();
+#endif
+ eeze_net_shutdown();
+ ecore_shutdown();
+ eina_log_domain_unregister(_eeze_udev_log_dom);
+ _eeze_udev_log_dom = -1;
+ eina_shutdown();
+ return _eeze_init_count;
+}
+
diff --git a/src/lib/eeze_net.c b/src/lib/eeze_net.c
new file mode 100644
index 0000000..415f794
--- /dev/null
+++ b/src/lib/eeze_net.c
@@ -0,0 +1,321 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <Eeze_Net.h>
+
+#include "eeze_udev_private.h"
+#include "eeze_net_private.h"
+
+static Eina_Hash *eeze_nets = NULL;
+
+Eina_Bool
+eeze_net_init(void)
+{
+ eeze_nets = eina_hash_string_superfast_new(NULL);
+ return !!eeze_nets;
+}
+
+void
+eeze_net_shutdown(void)
+{
+ eina_hash_free(eeze_nets);
+ eeze_nets = NULL;
+}
+
+/** @addtogroup net Net
+ * @{
+ */
+
+/**
+ * @brief Create a new net object
+ * @param name The name of the underlying device (eth0, br1, etc)
+ * @return A newly allocated net object, or NULL on failure
+ *
+ * This function creates a new net object based on @p name.
+ * Only the most minimal lookups are performed at creation in order
+ * to save memory.
+ */
+Eeze_Net *
+eeze_net_new(const char *name)
+{
+ const char *syspath = NULL;
+ const char *idx;
+ _udev_enumerate *en;
+ _udev_list_entry *devs, *cur;
+ _udev_device *device = NULL;
+ Eeze_Net *net;
+
+ net = eina_hash_find(eeze_nets, name);
+ if (net)
+ {
+ EINA_REFCOUNT_REF(net);
+ return net;
+ }
+
+ en = udev_enumerate_new(udev);
+ udev_enumerate_add_match_sysname(en, name);
+ udev_enumerate_add_match_subsystem(en, "net");
+ udev_enumerate_scan_devices(en);
+ devs = udev_enumerate_get_list_entry(en);
+ udev_list_entry_foreach(cur, devs)
+ {
+ const char *devname, *test;
+
+ devname = udev_list_entry_get_name(cur);
+ test = strrchr(devname, '/');
+ if (strcmp(++test, name)) continue;
+ device = _new_device(devname);
+ syspath = eina_stringshare_add(name);
+ break;
+ }
+ if (!device) return NULL;
+ net = calloc(1, sizeof(Eeze_Net));
+ if (!net) return NULL;
+ EINA_REFCOUNT_INIT(net);
+ net->device = device;
+ net->syspath = syspath;
+ net->name = eina_stringshare_add(name);
+ idx = udev_device_get_sysattr_value(net->device, "ifindex");
+ net->index = atoi(idx);
+ eina_hash_add(eeze_nets, name, net);
+ udev_enumerate_unref(en);
+ return net;
+}
+
+/**
+ * @brief Free a net object
+ * @param net The object to free
+ *
+ * Use this function to free a net object.
+ * @see eeze_net_new()
+ * @see eeze_net_list()
+ */
+void
+eeze_net_free(Eeze_Net *net)
+{
+ EINA_SAFETY_ON_NULL_RETURN(net);
+
+ EINA_REFCOUNT_UNREF(net)
+ {
+ eina_hash_del_by_key(eeze_nets, net->name);
+ udev_device_unref(net->device);
+ eina_stringshare_del(net->syspath);
+ eina_stringshare_del(net->name);
+ eina_stringshare_del(net->ip);
+ eina_stringshare_del(net->broadip);
+ eina_stringshare_del(net->netmask);
+#ifdef HAVE_IPV6
+ eina_stringshare_del(net->ip6);
+ eina_stringshare_del(net->broadip6);
+ eina_stringshare_del(net->netmask6);
+#endif
+ free(net);
+ }
+}
+
+/**
+ * @brief Get the MAC address of a net object
+ * @param net The net object
+ * @return The MAC address, NULL on failure
+ * Use this function to retrieve the non-stringshared MAC address of @p net.
+ */
+const char *
+eeze_net_mac_get(Eeze_Net *net)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(net, NULL);
+
+ return udev_device_get_sysattr_value(net->device, "address");
+}
+
+/**
+ * @brief Get the index of a net object
+ * @param net The net object
+ * @return The ifindex of the object, -1 on failure
+ * Use this function to get the hardware index of @p net
+ */
+int
+eeze_net_idx_get(Eeze_Net *net)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(net, -1);
+ return net->index;
+}
+
+/**
+ * @brief Scan an interface to cache its network addresses
+ * @param net The net object to scan
+ * @return EINA_TRUE on success, EINA_FALSE on failure
+ * Use this function to scan and cache the ip address, netmask, and broadcast
+ * address for an interface. This function will perform a full scan every time
+ * it is called, and IPv6 addresses will be cached if Eeze was compiled with IPv6
+ * support was enabled at compile time.
+ * @see eeze_net_addr_get()
+ */
+Eina_Bool
+eeze_net_scan(Eeze_Net *net)
+{
+ char ip[INET_ADDRSTRLEN];
+#ifdef HAVE_IPV6
+ char ip6[INET6_ADDRSTRLEN];
+ struct sockaddr_in6 *sa6;
+#endif
+ int sock;
+ int ioctls[3] = {SIOCGIFADDR, SIOCGIFBRDADDR, SIOCGIFNETMASK}, *i = ioctls;
+ struct ifreq ifr;
+ struct sockaddr_in *sa;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(net, EINA_FALSE);
+
+ /* ensure that we have the right name, mostly for hahas */
+ if_indextoname((unsigned int)net->index, ifr.ifr_name);
+ ifr.ifr_addr.sa_family = AF_INET;
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0) return EINA_FALSE;
+
+ if (ioctl(sock, *i++, &ifr) < 0) goto error;
+ sa = (struct sockaddr_in*) & (ifr.ifr_addr);
+ inet_ntop(AF_INET, (struct in_addr*)&sa->sin_addr, ip, INET_ADDRSTRLEN);
+ eina_stringshare_replace_length(&net->ip, ip, INET_ADDRSTRLEN);
+
+ if (ioctl(sock, *i++, &ifr) < 0) goto error;
+ sa = (struct sockaddr_in*) & (ifr.ifr_broadaddr);
+ inet_ntop(AF_INET, (struct in_addr*)&sa->sin_addr, ip, INET_ADDRSTRLEN);
+ eina_stringshare_replace_length(&net->broadip, ip, INET_ADDRSTRLEN);
+
+ if (ioctl(sock, *i++, &ifr) < 0) goto error;
+ sa = (struct sockaddr_in*) & (ifr.ifr_netmask);
+ inet_ntop(AF_INET, (struct in_addr*)&sa->sin_addr, ip, INET_ADDRSTRLEN);
+ eina_stringshare_replace_length(&net->netmask, ip, INET_ADDRSTRLEN);
+
+ close(sock);
+#ifdef HAVE_IPV6
+ i = ioctls;
+ ifr.ifr_addr.sa_family = AF_INET6;
+ sock = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (sock < 0) return EINA_FALSE;
+
+ if (ioctl(sock, *i++, &ifr) < 0) goto error;
+ sa6 = (struct sockaddr_in6*) & (ifr.ifr_addr);
+ inet_ntop(AF_INET6, (struct in6_addr*)&sa6->sin6_addr, ip6, INET6_ADDRSTRLEN);
+ eina_stringshare_replace_length(&net->ip6, ip6, INET6_ADDRSTRLEN);
+
+ if (ioctl(sock, *i++, &ifr) < 0) goto error;
+ sa6 = (struct sockaddr_in6*) & (ifr.ifr_broadaddr);
+ inet_ntop(AF_INET6, (struct in6_addr*)&sa6->sin6_addr, ip6, INET6_ADDRSTRLEN);
+ eina_stringshare_replace_length(&net->broadip6, ip6, INET6_ADDRSTRLEN);
+
+ if (ioctl(sock, *i++, &ifr) < 0) goto error;
+ sa6 = (struct sockaddr_in6*) & (ifr.ifr_netmask);
+ inet_ntop(AF_INET6, (struct in6_addr*)&sa6->sin6_addr, ip6, INET6_ADDRSTRLEN);
+ eina_stringshare_replace_length(&net->netmask6, ip6, INET6_ADDRSTRLEN);
+
+ close(sock);
+#endif
+
+ return EINA_TRUE;
+error:
+ close(sock);
+ return EINA_FALSE;
+}
+
+/**
+ * @brief Get the address of a net object
+ * @param net The net object
+ * @param type The type of address to retrieve
+ * @return The stringshared address for @p net corresponding to @p type, NULL on failure
+ * This function returns a value previously cached.
+ * @see eeze_net_scan()
+ */
+const char *
+eeze_net_addr_get(Eeze_Net *net, Eeze_Net_Addr_Type type)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(net, NULL);
+
+ switch (type)
+ {
+ case EEZE_NET_ADDR_TYPE_IP6:
+#ifdef HAVE_IPV6
+ return net->ip6;
+#else
+ return NULL;
+#endif
+ case EEZE_NET_ADDR_TYPE_BROADCAST:
+ return net->broadip;
+ case EEZE_NET_ADDR_TYPE_BROADCAST6:
+#ifdef HAVE_IPV6
+ return net->broadip6;
+#else
+ return NULL;
+#endif
+ case EEZE_NET_ADDR_TYPE_NETMASK:
+ return net->netmask;
+ case EEZE_NET_ADDR_TYPE_NETMASK6:
+#ifdef HAVE_IPV6
+ return net->netmask6;
+#else
+ return NULL;
+#endif
+ default:
+ break;
+ }
+ return net->ip;
+}
+
+/**
+ * @brief Get a system attribute of a net object
+ * @param net The net object
+ * @param attr The attribute to retrieve
+ * @return The non-stringshared value of the attribute, NULL on failure
+ * Use this function to perform a udev sysattr lookup on the underlying device of @p net
+ */
+const char *
+eeze_net_attribute_get(Eeze_Net *net, const char *attr)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(net, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(attr, NULL);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(!attr[0], NULL);
+
+ return udev_device_get_sysattr_value(net->device, attr);
+}
+
+/**
+ * @brief Get the /sys/ path of a net object
+ * @param net The net object
+ * @return The stringshared /sys/ path of the interface, NULL on failure
+ */
+const char *
+eeze_net_syspath_get(Eeze_Net *net)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(net, NULL);
+
+ return net->syspath;
+}
+
+/**
+ * @brief Get a list of all the network interfaces available
+ * @return A list of Eeze_Net objects
+ * Use this function to get all network interfaces available to the application.
+ * This list must be freed by the user.
+ */
+Eina_List *
+eeze_net_list(void)
+{
+ struct if_nameindex *ifs, *i;
+ Eina_List *ret = NULL;
+ Eeze_Net *net;
+
+ ifs = if_nameindex();
+ for (i = ifs; i && i->if_name && i->if_name[0]; i++)
+ {
+ net = eeze_net_new(i->if_name);
+ if (net) ret = eina_list_append(ret, net);
+ }
+
+ if_freenameindex(ifs);
+ return ret;
+}
+/** @} */
diff --git a/src/lib/eeze_net_private.h b/src/lib/eeze_net_private.h
new file mode 100644
index 0000000..d9b8faf
--- /dev/null
+++ b/src/lib/eeze_net_private.h
@@ -0,0 +1,53 @@
+#ifndef EEZE_NET_PRIVATE_H
+#define EEZE_NET_PRIVATE_H
+#include <Eeze.h>
+#include "eeze_udev_private.h"
+
+#ifndef EEZE_NET_COLOR_DEFAULT
+#define EEZE_NET_COLOR_DEFAULT EINA_COLOR_GREEN
+#endif
+extern int _eeze_net_log_dom;
+#ifdef CRI
+#undef CRI
+#endif
+
+#ifdef ERR
+#undef ERR
+#endif
+#ifdef INF
+#undef INF
+#endif
+#ifdef WARN
+#undef WARN
+#endif
+#ifdef DBG
+#undef DBG
+#endif
+
+#define CRI(...) EINA_LOG_DOM_CRIT(_eeze_net_log_dom, __VA_ARGS__)
+#define DBG(...) EINA_LOG_DOM_DBG(_eeze_net_log_dom, __VA_ARGS__)
+#define INF(...) EINA_LOG_DOM_INFO(_eeze_net_log_dom, __VA_ARGS__)
+#define WARN(...) EINA_LOG_DOM_WARN(_eeze_net_log_dom, __VA_ARGS__)
+#define ERR(...) EINA_LOG_DOM_ERR(_eeze_net_log_dom, __VA_ARGS__)
+
+struct Eeze_Net
+{
+ EINA_REFCOUNT;
+ int index;
+ _udev_device *device;
+ const char *syspath;
+ const char *name;
+
+ const char *ip;
+ const char *broadip;
+ const char *netmask;
+#ifdef HAVE_IPV6
+ const char *ip6;
+ const char *broadip6;
+ const char *netmask6;
+#endif
+};
+
+Eina_Bool eeze_net_init(void);
+void eeze_net_shutdown(void);
+#endif
diff --git a/src/lib/eeze_udev_find.c b/src/lib/eeze_udev_find.c
new file mode 100644
index 0000000..3bd06ab
--- /dev/null
+++ b/src/lib/eeze_udev_find.c
@@ -0,0 +1,384 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <Eeze.h>
+#include "eeze_udev_private.h"
+
+EAPI Eina_List *
+eeze_udev_find_similar_from_syspath(const char *syspath)
+{
+ _udev_device *device;
+ _udev_list_entry *devs, *cur;
+ _udev_enumerate *en;
+ Eina_List *l, *ret = NULL;
+ const char *vendor, *model, *revision, *devname, *dev;
+
+ if (!syspath)
+ return NULL;
+
+ en = udev_enumerate_new(udev);
+
+ if (!en)
+ return NULL;
+
+ if (!(device = _new_device(syspath)))
+ return NULL;
+
+ vendor = udev_device_get_property_value(device, "ID_VENDOR_ID");
+
+ if (vendor)
+ udev_enumerate_add_match_property(en, "ID_VENDOR_ID", vendor);
+
+ model = udev_device_get_property_value(device, "ID_MODEL_ID");
+
+ if (model)
+ udev_enumerate_add_match_property(en, "ID_MODEL_ID", model);
+
+ revision = udev_device_get_property_value(device, "ID_REVISION");
+
+ if (revision)
+ udev_enumerate_add_match_property(en, "ID_REVISION", revision);
+
+ udev_enumerate_scan_devices(en);
+ udev_device_unref(device);
+ devs = udev_enumerate_get_list_entry(en);
+ udev_list_entry_foreach(cur, devs)
+ {
+ devname = udev_list_entry_get_name(cur);
+ /* verify unlisted device */
+
+ EINA_LIST_FOREACH(ret, l, dev)
+ if (!strcmp(dev, devname))
+ continue;
+
+ ret = eina_list_prepend(ret, eina_stringshare_add(devname));
+ device = udev_device_new_from_syspath(udev, devname);
+
+ /* only device roots have this sysattr,
+ * and we only need to check parents of the roots
+ */
+ if (udev_device_get_sysattr_value(device, "idVendor"))
+ ret = _get_unlisted_parents(ret, device);
+
+ udev_device_unref(device);
+ }
+ udev_enumerate_unref(en);
+ return ret;
+}
+
+EAPI Eina_List *
+eeze_udev_find_unlisted_similar(Eina_List *list)
+{
+ _udev_device *device;
+ _udev_list_entry *devs, *cur;
+ _udev_enumerate *en;
+ Eina_List *l;
+ const char *vendor, *model, *revision, *devname, *dev;
+
+ if (!list)
+ return NULL;
+
+ EINA_LIST_FOREACH(list, l, dev)
+ {
+ en = udev_enumerate_new(udev);
+
+ if (!en)
+ return NULL;
+
+ device = _new_device(dev);
+ if (!device) continue;
+
+ if ((vendor = udev_device_get_property_value(device, "ID_VENDOR_ID")))
+ udev_enumerate_add_match_property(en, "ID_VENDOR_ID", vendor);
+ else if ((vendor = udev_device_get_property_value(device, "ID_VENDOR")))
+ udev_enumerate_add_match_property(en, "ID_VENDOR", vendor);
+ else if ((vendor = udev_device_get_sysattr_value(device, "vendor")))
+ udev_enumerate_add_match_sysattr(en, "vendor", vendor);
+ else if ((vendor = udev_device_get_sysattr_value(device, "manufacturer")))
+ udev_enumerate_add_match_sysattr(en, "manufacturer", vendor);
+
+ if ((model = udev_device_get_property_value(device, "ID_MODEL_ID")))
+ udev_enumerate_add_match_property(en, "ID_MODEL_ID", model);
+ else if ((model = udev_device_get_property_value(device, "ID_MODEL")))
+ udev_enumerate_add_match_property(en, "ID_MODEL", model);
+ else if ((model = udev_device_get_sysattr_value(device, "model")))
+ udev_enumerate_add_match_sysattr(en, "model", model);
+ else if ((model = udev_device_get_sysattr_value(device, "product")))
+ udev_enumerate_add_match_sysattr(en, "product", model);
+
+ if ((revision = udev_device_get_property_value(device, "ID_REVISION")))
+ udev_enumerate_add_match_property(en, "ID_REVISION", revision);
+ else if ((revision = udev_device_get_sysattr_value(device, "revision")))
+ udev_enumerate_add_match_sysattr(en, "revision", revision);
+
+ udev_enumerate_add_match_subsystem(en, udev_device_get_subsystem(device));
+
+ udev_enumerate_scan_devices(en);
+ udev_device_unref(device);
+ devs = udev_enumerate_get_list_entry(en);
+ udev_list_entry_foreach(cur, devs)
+ {
+ devname = udev_list_entry_get_name(cur);
+ device = udev_device_new_from_syspath(udev, devname);
+
+ /* only device roots have this sysattr,
+ * and we only need to check parents of the roots
+ */
+ if (udev_device_get_sysattr_value(device, "idVendor"))
+ list = _get_unlisted_parents(list, device);
+
+ udev_device_unref(device);
+ }
+ udev_enumerate_unref(en);
+ }
+ return list;
+}
+
+EAPI Eina_List *
+eeze_udev_find_by_type(Eeze_Udev_Type etype,
+ const char *name)
+{
+ _udev_enumerate *en;
+ _udev_list_entry *devs, *cur;
+ _udev_device *device, *parent;
+ const char *devname;
+ Eina_List *ret = NULL;
+
+ if ((!etype) && (!name))
+ return NULL;
+
+ en = udev_enumerate_new(udev);
+
+ if (!en)
+ return NULL;
+
+ switch (etype)
+ {
+ case EEZE_UDEV_TYPE_NONE:
+ break;
+
+ case EEZE_UDEV_TYPE_KEYBOARD:
+ udev_enumerate_add_match_subsystem(en, "input");
+#ifndef OLD_UDEV_RRRRRRRRRRRRRR
+ udev_enumerate_add_match_property(en, "ID_INPUT_KEYBOARD", "1");
+#else
+ udev_enumerate_add_match_property(en, "ID_CLASS", "kbd");
+#endif
+ break;
+
+ case EEZE_UDEV_TYPE_MOUSE:
+ udev_enumerate_add_match_subsystem(en, "input");
+#ifndef OLD_UDEV_RRRRRRRRRRRRRR
+ udev_enumerate_add_match_property(en, "ID_INPUT_MOUSE", "1");
+#else
+ udev_enumerate_add_match_property(en, "ID_CLASS", "mouse");
+#endif
+ break;
+
+ case EEZE_UDEV_TYPE_TOUCHPAD:
+ udev_enumerate_add_match_subsystem(en, "input");
+#ifndef OLD_UDEV_RRRRRRRRRRRRRR
+ udev_enumerate_add_match_property(en, "ID_INPUT_TOUCHPAD", "1");
+#endif
+ break;
+
+ case EEZE_UDEV_TYPE_JOYSTICK:
+ udev_enumerate_add_match_subsystem(en, "input");
+#ifndef OLD_UDEV_RRRRRRRRRRRRRR
+ udev_enumerate_add_match_property(en, "ID_INPUT_JOYSTICK", "1");
+#endif
+ break;
+
+ case EEZE_UDEV_TYPE_DRIVE_MOUNTABLE:
+ udev_enumerate_add_match_subsystem(en, "block");
+ udev_enumerate_add_match_property(en, "ID_FS_USAGE", "filesystem");
+ break;
+
+ case EEZE_UDEV_TYPE_DRIVE_INTERNAL:
+ udev_enumerate_add_match_subsystem(en, "block");
+ udev_enumerate_add_match_property(en, "ID_TYPE", "disk");
+ udev_enumerate_add_match_property(en, "ID_BUS", "ata");
+ udev_enumerate_add_match_sysattr(en, "removable", "0");
+ break;
+
+ case EEZE_UDEV_TYPE_DRIVE_REMOVABLE:
+ udev_enumerate_add_match_sysattr(en, "removable", "1");
+ udev_enumerate_add_match_property(en, "ID_TYPE", "disk");
+ break;
+
+ case EEZE_UDEV_TYPE_DRIVE_CDROM:
+ udev_enumerate_add_match_property(en, "ID_CDROM", "1");
+ break;
+
+ case EEZE_UDEV_TYPE_POWER_AC:
+ udev_enumerate_add_match_subsystem(en, "power_supply");
+ udev_enumerate_add_match_sysattr(en, "type", "Mains");
+ break;
+
+ case EEZE_UDEV_TYPE_POWER_BAT:
+ udev_enumerate_add_match_subsystem(en, "power_supply");
+ udev_enumerate_add_match_sysattr(en, "type", "Battery");
+ udev_enumerate_add_match_sysattr(en, "present", "1");
+ break;
+
+ case EEZE_UDEV_TYPE_NET:
+ udev_enumerate_add_match_subsystem(en, "net");
+ break;
+
+ case EEZE_UDEV_TYPE_IS_IT_HOT_OR_IS_IT_COLD_SENSOR:
+ udev_enumerate_add_match_subsystem(en, "hwmon");
+ break;
+
+ /*
+ case EEZE_UDEV_TYPE_ANDROID:
+ udev_enumerate_add_match_subsystem(en, "block");
+ udev_enumerate_add_match_property(en, "ID_MODEL", "Android_*");
+ break;
+ */
+ case EEZE_UDEV_TYPE_V4L:
+ udev_enumerate_add_match_subsystem(en, "video4linux");
+ break;
+ case EEZE_UDEV_TYPE_BLUETOOTH:
+ udev_enumerate_add_match_subsystem(en, "bluetooth");
+ break;
+ default:
+ break;
+ }
+
+ udev_enumerate_scan_devices(en);
+ devs = udev_enumerate_get_list_entry(en);
+ udev_list_entry_foreach(cur, devs)
+ {
+ devname = udev_list_entry_get_name(cur);
+ device = udev_device_new_from_syspath(udev, devname);
+
+ if (etype == EEZE_UDEV_TYPE_IS_IT_HOT_OR_IS_IT_COLD_SENSOR) /* ensure that temp input exists somewhere in this device chain */
+ {
+ Eina_Bool one, two;
+ const char *t;
+
+ one = _walk_parents_test_attr(device, "temp1_input", NULL);
+ two = _walk_parents_test_attr(device, "temp2_input", NULL);
+ if ((!one) && (!two)) goto out;
+
+ t = one ? "temp1_input" : "temp2_input";
+ /* if device is not the one which has the temp input, we must go up the chain */
+ if (!udev_device_get_sysattr_value(device, t))
+ {
+ devname = NULL;
+
+ for (parent = udev_device_get_parent(device); parent; parent = udev_device_get_parent(parent)) /*check for parent */
+ if ((udev_device_get_sysattr_value(parent, t)))
+ {
+ devname = udev_device_get_syspath(parent);
+ break;
+ }
+
+ if (!devname)
+ goto out;
+ }
+ }
+ else if (etype == EEZE_UDEV_TYPE_DRIVE_REMOVABLE)
+ {
+ /* this yields the actual hw device, not to be confused with the filesystem */
+ devname = udev_device_get_syspath(udev_device_get_parent(device));
+ }
+ else if (etype == EEZE_UDEV_TYPE_DRIVE_MOUNTABLE)
+ {
+ int devcheck;
+
+ devcheck = open(udev_device_get_devnode(device), O_RDONLY);
+ if (devcheck < 0) goto out;
+ close(devcheck);
+ }
+
+ if (name && (!strstr(devname, name)))
+ goto out;
+
+ ret = eina_list_append(ret, eina_stringshare_add(devname));
+out:
+ udev_device_unref(device);
+ }
+ udev_enumerate_unref(en);
+ return ret;
+}
+
+EAPI Eina_List *
+eeze_udev_find_by_filter(const char *subsystem,
+ const char *type,
+ const char *name)
+{
+ _udev_enumerate *en;
+ _udev_list_entry *devs, *cur;
+ _udev_device *device;
+ const char *devname;
+ Eina_List *ret = NULL;
+
+ if ((!subsystem) && (!type) && (!name))
+ return NULL;
+
+ en = udev_enumerate_new(udev);
+
+ if (!en)
+ return NULL;
+
+ if (subsystem)
+ udev_enumerate_add_match_subsystem(en, subsystem);
+
+ udev_enumerate_add_match_property(en, type, "1");
+ udev_enumerate_scan_devices(en);
+ devs = udev_enumerate_get_list_entry(en);
+ udev_list_entry_foreach(cur, devs)
+ {
+ devname = udev_list_entry_get_name(cur);
+ device = udev_device_new_from_syspath(udev, devname);
+
+ if (name)
+ if (!strstr(devname, name))
+ goto out;
+
+ ret = eina_list_append(ret, eina_stringshare_add(devname));
+out:
+ udev_device_unref(device);
+ }
+ udev_enumerate_unref(en);
+ return ret;
+}
+
+EAPI Eina_List *
+eeze_udev_find_by_sysattr(const char *sysattr,
+ const char *value)
+{
+ _udev_enumerate *en;
+ _udev_list_entry *devs, *cur;
+ _udev_device *device;
+ const char *devname;
+ Eina_List *ret = NULL;
+
+ if (!sysattr)
+ return NULL;
+
+ en = udev_enumerate_new(udev);
+
+ if (!en)
+ return NULL;
+
+ udev_enumerate_add_match_sysattr(en, sysattr, value);
+ udev_enumerate_scan_devices(en);
+ devs = udev_enumerate_get_list_entry(en);
+ udev_list_entry_foreach(cur, devs)
+ {
+ devname = udev_list_entry_get_name(cur);
+ device = udev_device_new_from_syspath(udev, devname);
+ ret = eina_list_append(ret, eina_stringshare_add(devname));
+ udev_device_unref(device);
+ }
+ udev_enumerate_unref(en);
+ return ret;
+}
diff --git a/src/lib/eeze_udev_private.c b/src/lib/eeze_udev_private.c
new file mode 100644
index 0000000..7e5b5dd
--- /dev/null
+++ b/src/lib/eeze_udev_private.c
@@ -0,0 +1,200 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <Eeze.h>
+#include "eeze_udev_private.h"
+
+/*
+ * helper function to set up a new device from a syspath
+ * which may or may not include /sys at the beginning
+ */
+_udev_device *
+_new_device(const char *syspath)
+{
+ _udev_device *device;
+
+ device = udev_device_new_from_syspath(udev, syspath);
+ if (!device)
+ ERR("device %s does not exist!", syspath);
+ return device;
+}
+
+/*
+ * copies a device
+ */
+_udev_device *
+_copy_device(_udev_device *device)
+{
+ return udev_device_ref(device);
+}
+
+/*
+ * private function to simulate udevadm info -a
+ * walks up the device tree checking each node for sysattr
+ * with value $value
+ */
+Eina_Bool
+_walk_parents_test_attr(_udev_device *device,
+ const char *sysattr,
+ const char *value)
+{
+ _udev_device *parent, *child = device;
+ const char *test;
+
+ if (udev_device_get_sysattr_value(device, sysattr))
+ return EINA_TRUE;
+
+ parent = udev_device_get_parent(child);
+
+ for (; parent; child = parent, parent = udev_device_get_parent(child))
+ {
+ if (!(test = udev_device_get_sysattr_value(parent, sysattr)))
+ continue;
+
+ if (!value)
+ return EINA_TRUE;
+ else
+ if (!strcmp(test, value))
+ return EINA_TRUE;
+ }
+
+ return EINA_FALSE;
+}
+
+const char *
+_walk_parents_get_attr(_udev_device *device,
+ const char *sysattr,
+ Eina_Bool property)
+{
+ _udev_device *parent, *child = device;
+ const char *test;
+
+ if (property)
+ test = udev_device_get_property_value(device, sysattr);
+ else
+ test = udev_device_get_sysattr_value(device, sysattr);
+ if (test) return eina_stringshare_add(test);
+
+ parent = udev_device_get_parent(child);
+
+ for (; parent; child = parent, parent = udev_device_get_parent(child))
+ {
+ if (property)
+ test = udev_device_get_property_value(parent, sysattr);
+ else
+ test = udev_device_get_sysattr_value(parent, sysattr);
+ if (test) return eina_stringshare_add(test);
+ }
+
+ return NULL;
+}
+
+const char *
+_walk_children_get_attr(const char *syspath,
+ const char *sysattr,
+ const char *subsystem,
+ Eina_Bool property)
+{
+ char buf[PATH_MAX];
+ const char *path, *ret = NULL;
+ _udev_enumerate *en;
+ _udev_list_entry *devs, *cur;
+
+ en = udev_enumerate_new(udev);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(en, NULL);
+ path = strrchr(syspath, '/');
+ if (path) path++;
+ else path = syspath;
+ snprintf(buf, sizeof(buf), "%s*", path);
+ udev_enumerate_add_match_sysname(en, buf);
+ if (subsystem) udev_enumerate_add_match_subsystem(en, subsystem);
+ udev_enumerate_scan_devices(en);
+ devs = udev_enumerate_get_list_entry(en);
+ udev_list_entry_foreach(cur, devs)
+ {
+ const char *devname, *test;
+ _udev_device *device;
+
+ devname = udev_list_entry_get_name(cur);
+ device = _new_device(devname);
+ if (property)
+ test = udev_device_get_property_value(device, sysattr);
+ else
+ test = udev_device_get_sysattr_value(device, sysattr);
+ if (test)
+ {
+ ret = eina_stringshare_add(test);
+ udev_device_unref(device);
+ break;
+ }
+ udev_device_unref(device);
+ }
+ udev_enumerate_unref(en);
+ return ret;
+}
+
+/*
+ * check a list for all parents of a device,
+ * stringshare adding all devices that are not in the list
+ */
+Eina_List *
+_get_unlisted_parents(Eina_List *list,
+ _udev_device *device)
+{
+ _udev_device *parent, *child = device;
+ const char *test, *devname, *vendor, *vendor2, *model, *model2;
+ Eina_List *l;
+ Eina_Bool found;
+
+ if (!(vendor = udev_device_get_property_value(child, "ID_VENDOR_ID")))
+ vendor = udev_device_get_property_value(child, "ID_VENDOR");
+ if (!vendor) vendor = udev_device_get_sysattr_value(child, "vendor");
+ if (!vendor) vendor = udev_device_get_sysattr_value(child, "manufacturer");
+
+ if (!(model = udev_device_get_property_value(child, "ID_MODEL_ID")))
+ model = udev_device_get_property_value(child, "ID_MODEL");
+ if (!model) model = udev_device_get_sysattr_value(child, "model");
+ if (!model) model = udev_device_get_sysattr_value(child, "product");
+
+ parent = udev_device_get_parent(child);
+
+ for (; parent; child = parent, parent = udev_device_get_parent(child))
+ {
+ found = EINA_FALSE;
+
+ if (!(vendor2 = udev_device_get_property_value(child, "ID_VENDOR_ID")))
+ vendor2 = udev_device_get_property_value(child, "ID_VENDOR");
+ if (!vendor2) vendor2 = udev_device_get_sysattr_value(child, "vendor");
+ if (!vendor2) vendor2 = udev_device_get_sysattr_value(child, "manufacturer");
+
+ if (!(model2 = udev_device_get_property_value(child, "ID_MODEL_ID")))
+ model2 = udev_device_get_property_value(child, "ID_MODEL");
+ if (!model2) model2 = udev_device_get_sysattr_value(child, "model");
+ if (!model2) model2 = udev_device_get_sysattr_value(child, "product");
+
+ if ((!model2 && model) || (model2 && !model) || (!vendor2 && vendor)
+ || (vendor2 && !vendor))
+ break;
+ else
+ if (((model && model2) && (strcmp(model, model2))) ||
+ ((vendor && vendor2) && (strcmp(vendor, vendor2))))
+ break;
+
+ devname = udev_device_get_syspath(parent);
+ EINA_LIST_FOREACH(list, l, test)
+ {
+ if (!strcmp(test, devname))
+ {
+ found = EINA_TRUE;
+ break;
+ }
+ }
+
+ if (!found)
+ list = eina_list_prepend(list, eina_stringshare_add(devname));
+ }
+
+ return list;
+}
+
diff --git a/src/lib/eeze_udev_private.h b/src/lib/eeze_udev_private.h
new file mode 100644
index 0000000..59aacbd
--- /dev/null
+++ b/src/lib/eeze_udev_private.h
@@ -0,0 +1,46 @@
+#ifndef EEZE_UDEV_PRIVATE_H
+#define EEZE_UDEV_PRIVATE_H
+#include <Eeze.h>
+
+#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE 1
+#include <libudev.h>
+
+#ifndef EEZE_UDEV_COLOR_DEFAULT
+#define EEZE_UDEV_COLOR_DEFAULT EINA_COLOR_CYAN
+#endif
+extern int _eeze_udev_log_dom;
+#ifdef ERR
+#undef ERR
+#endif
+#ifdef INF
+#undef INF
+#endif
+#ifdef WARN
+#undef WARN
+#endif
+#ifdef DBG
+#undef DBG
+#endif
+
+#define DBG(...) EINA_LOG_DOM_DBG(_eeze_udev_log_dom, __VA_ARGS__)
+#define INF(...) EINA_LOG_DOM_INFO(_eeze_udev_log_dom, __VA_ARGS__)
+#define WARN(...) EINA_LOG_DOM_WARN(_eeze_udev_log_dom, __VA_ARGS__)
+#define ERR(...) EINA_LOG_DOM_ERR(_eeze_udev_log_dom, __VA_ARGS__)
+
+/* typedefs because I'm lazy */
+typedef struct udev _udev;
+typedef struct udev_list_entry _udev_list_entry;
+typedef struct udev_device _udev_device;
+typedef struct udev_enumerate _udev_enumerate;
+typedef struct udev_monitor _udev_monitor;
+
+extern _udev *udev;
+
+_udev_device *_new_device(const char *syspath);
+const char *_walk_children_get_attr(const char *syspath, const char *sysattr, const char *subsystem, Eina_Bool property);
+Eina_Bool _walk_parents_test_attr(_udev_device *device, const char *sysattr, const char* value);
+const char *_walk_parents_get_attr(_udev_device *device, const char *sysattr, Eina_Bool property);
+Eina_List *_get_unlisted_parents(Eina_List *list, _udev_device *device);
+_udev_device *_copy_device(_udev_device *device);
+
+#endif
diff --git a/src/lib/eeze_udev_syspath.c b/src/lib/eeze_udev_syspath.c
new file mode 100644
index 0000000..df858e6
--- /dev/null
+++ b/src/lib/eeze_udev_syspath.c
@@ -0,0 +1,292 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <Eeze.h>
+#include "eeze_udev_private.h"
+
+EAPI const char *
+eeze_udev_syspath_get_parent(const char *syspath)
+{
+ _udev_device *device, *parent;
+ const char *ret;
+
+ if (!syspath)
+ return NULL;
+
+ if (!(device = _new_device(syspath)))
+ return NULL;
+ parent = udev_device_get_parent(device);
+ ret = eina_stringshare_add(udev_device_get_syspath(parent));
+ udev_device_unref(device);
+ return ret;
+}
+
+EAPI Eina_List *
+eeze_udev_syspath_get_parents(const char *syspath)
+{
+ _udev_device *child, *parent, *device;
+ const char *path;
+ Eina_List *devlist = NULL;
+
+ if (!syspath)
+ return NULL;
+
+ if (!(device = _new_device(syspath)))
+ return NULL;
+
+ if (!(parent = udev_device_get_parent(device)))
+ return NULL;
+
+ for (; parent; child = parent, parent = udev_device_get_parent(child))
+ {
+ path = udev_device_get_syspath(parent);
+ devlist = eina_list_append(devlist, eina_stringshare_add(path));
+ }
+
+ udev_device_unref(device);
+ return devlist;
+}
+
+EAPI const char *
+eeze_udev_syspath_get_devpath(const char *syspath)
+{
+ _udev_device *device;
+ const char *name = NULL;
+
+ if (!syspath)
+ return NULL;
+
+ if (!(device = _new_device(syspath)))
+ return NULL;
+
+ if (!(name = udev_device_get_devnode(device)))
+ return NULL;
+
+ name = eina_stringshare_add(name);
+ udev_device_unref(device);
+ return name;
+}
+
+EAPI const char *
+eeze_udev_syspath_get_devname(const char *syspath)
+{
+ _udev_device *device;
+ const char *name = NULL;
+
+ if (!syspath)
+ return NULL;
+
+ if (!(device = _new_device(syspath)))
+ return NULL;
+
+ if (!(name = udev_device_get_sysname(device)))
+ return NULL;
+
+ name = eina_stringshare_add(name);
+ udev_device_unref(device);
+ return name;
+}
+
+EAPI const char *
+eeze_udev_syspath_get_subsystem(const char *syspath)
+{
+ _udev_device *device;
+ const char *subsystem;
+
+ if (!syspath)
+ return NULL;
+
+ if (!(device = _new_device(syspath)))
+ return NULL;
+ subsystem = eina_stringshare_add(udev_device_get_property_value(device, "SUBSYSTEM"));
+ udev_device_unref(device);
+ return subsystem;
+}
+
+EAPI const char *
+eeze_udev_syspath_get_property(const char *syspath,
+ const char *property)
+{
+ _udev_device *device;
+ const char *value = NULL, *test;
+
+ if (!syspath || !property)
+ return NULL;
+
+ if (!(device = _new_device(syspath)))
+ return NULL;
+ if ((test = udev_device_get_property_value(device, property)))
+ value = eina_stringshare_add(test);
+
+ udev_device_unref(device);
+ return value;
+}
+
+EAPI const char *
+eeze_udev_syspath_get_sysattr(const char *syspath,
+ const char *sysattr)
+{
+ _udev_device *device;
+ const char *value = NULL, *test;
+
+ if (!syspath || !sysattr)
+ return NULL;
+
+ if (!(device = _new_device(syspath)))
+ return NULL;
+
+ if ((test = udev_device_get_sysattr_value(device, sysattr)))
+ value = eina_stringshare_add(test);
+
+ udev_device_unref(device);
+ return value;
+}
+
+EAPI Eina_Bool
+eeze_udev_syspath_is_mouse(const char *syspath)
+{
+ _udev_device *device = NULL;
+ Eina_Bool mouse = EINA_FALSE;
+ const char *test = NULL;
+
+ if (!syspath)
+ return EINA_FALSE;
+
+ if (!(device = _new_device(syspath)))
+ return EINA_FALSE;
+#ifdef OLD_UDEV_RRRRRRRRRRRRRR
+ mouse = _walk_parents_test_attr(device, "bInterfaceProtocol", "02");
+
+ if (!mouse)
+ {
+ test = udev_device_get_property_value(device, "ID_CLASS");
+
+ if ((test) && (!strcmp(test, "mouse")))
+ mouse = EINA_TRUE;
+ }
+
+#else
+ test = udev_device_get_property_value(device, "ID_INPUT_MOUSE");
+
+ if (test && (test[0] == '1'))
+ mouse = EINA_TRUE;
+
+#endif
+ udev_device_unref(device);
+ return mouse;
+}
+
+EAPI Eina_Bool
+eeze_udev_syspath_is_kbd(const char *syspath)
+{
+ _udev_device *device = NULL;
+ Eina_Bool kbd = EINA_FALSE;
+ const char *test = NULL;
+
+ if (!syspath)
+ return EINA_FALSE;
+
+ if (!(device = _new_device(syspath)))
+ return EINA_FALSE;
+#ifdef OLD_UDEV_RRRRRRRRRRRRRR
+ kbd = _walk_parents_test_attr(device, "bInterfaceProtocol", "01");
+
+ if (!kbd)
+ {
+ test = udev_device_get_property_value(device, "ID_CLASS");
+
+ if ((test) && (!strcmp(test, "kbd")))
+ kbd = EINA_TRUE;
+ }
+
+#else
+ test = udev_device_get_property_value(device, "ID_INPUT_KEYBOARD");
+
+ if (test && (test[0] == '1'))
+ kbd = EINA_TRUE;
+
+#endif
+ udev_device_unref(device);
+ return kbd;
+}
+
+EAPI Eina_Bool
+eeze_udev_syspath_is_touchpad(const char *syspath)
+{
+ _udev_device *device = NULL;
+ Eina_Bool touchpad = EINA_FALSE;
+
+ if (!syspath)
+ return EINA_FALSE;
+
+ if (!(device = _new_device(syspath)))
+ return EINA_FALSE;
+#ifdef OLD_UDEV_RRRRRRRRRRRRRR
+ touchpad = _walk_parents_test_attr(device, "resolution", NULL);
+#else
+ const char *test;
+ test = udev_device_get_property_value(device, "ID_INPUT_TOUCHPAD");
+
+ if (test && (test[0] == '1'))
+ touchpad = EINA_TRUE;
+
+#endif
+ udev_device_unref(device);
+ return touchpad;
+}
+
+EAPI Eina_Bool
+eeze_udev_syspath_is_joystick(const char *syspath)
+{
+ _udev_device *device = NULL;
+ Eina_Bool joystick = EINA_FALSE;
+ const char *test;
+
+ if (!syspath)
+ return EINA_FALSE;
+
+ if (!(device = _new_device(syspath)))
+ return EINA_FALSE;
+#ifdef OLD_UDEV_RRRRRRRRRRRRRR
+ test = udev_device_get_property_value(device, "ID_CLASS");
+
+ if ((test) && (!strcmp(test, "joystick")))
+ joystick = EINA_TRUE;
+#else
+ test = udev_device_get_property_value(device, "ID_INPUT_JOYSTICK");
+
+ if (test && (test[0] == '1'))
+ joystick = EINA_TRUE;
+
+#endif
+ udev_device_unref(device);
+ return joystick;
+}
+
+EAPI const char *
+eeze_udev_devpath_get_syspath(const char *devpath)
+{
+ _udev_enumerate *en;
+ _udev_list_entry *devs, *cur;
+ const char *ret = NULL;
+
+ if (!devpath)
+ return NULL;
+
+ en = udev_enumerate_new(udev);
+
+ if (!en)
+ return NULL;
+
+ udev_enumerate_add_match_property(en, "DEVNAME", devpath);
+ udev_enumerate_scan_devices(en);
+ devs = udev_enumerate_get_list_entry(en);
+ udev_list_entry_foreach(cur, devs)
+ {
+ ret = eina_stringshare_add(udev_list_entry_get_name(cur));
+ break; /*just in case there's more than one somehow */
+ }
+ udev_enumerate_unref(en);
+ return ret;
+}
diff --git a/src/lib/eeze_udev_walk.c b/src/lib/eeze_udev_walk.c
new file mode 100644
index 0000000..78e2aab
--- /dev/null
+++ b/src/lib/eeze_udev_walk.c
@@ -0,0 +1,65 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <Eeze.h>
+#include "eeze_udev_private.h"
+
+EAPI Eina_Bool
+eeze_udev_walk_check_sysattr(const char *syspath,
+ const char *sysattr,
+ const char *value)
+{
+ _udev_device *device, *child, *parent;
+ Eina_Bool ret = EINA_FALSE;
+ const char *test = NULL;
+
+ if (!udev)
+ return EINA_FALSE;
+
+ if (!(device = _new_device(syspath)))
+ return EINA_FALSE;
+
+ for (parent = device; parent;
+ child = parent, parent = udev_device_get_parent(child))
+ {
+ if (!(test = udev_device_get_sysattr_value(parent, sysattr)))
+ continue;
+ if ((value && (!strcmp(test, value))) || (!value))
+ {
+ ret = EINA_TRUE;
+ break;
+ }
+ }
+
+ udev_device_unref(device);
+ return ret;
+}
+
+EAPI const char *
+eeze_udev_walk_get_sysattr(const char *syspath,
+ const char *sysattr)
+{
+ _udev_device *device, *child, *parent;
+ const char *test = NULL;
+
+ if (!syspath)
+ return NULL;
+
+ if (!(device = _new_device(syspath)))
+ return NULL;
+
+ for (parent = device; parent;
+ child = parent, parent = udev_device_get_parent(child))
+ {
+ if ((test = udev_device_get_sysattr_value(parent, sysattr)))
+ {
+ test = eina_stringshare_add(test);
+ udev_device_unref(device);
+ return test;
+ }
+ }
+
+ udev_device_unref(device);
+ return NULL;
+}
diff --git a/src/lib/eeze_udev_watch.c b/src/lib/eeze_udev_watch.c
new file mode 100644
index 0000000..b89e2d6
--- /dev/null
+++ b/src/lib/eeze_udev_watch.c
@@ -0,0 +1,441 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <Ecore.h>
+#include <Eeze.h>
+#include "eeze_udev_private.h"
+
+/* opaque */
+struct Eeze_Udev_Watch
+{
+ _udev_monitor *mon;
+ Ecore_Fd_Handler *handler;
+ Eeze_Udev_Type type;
+ void *data;
+};
+
+/* private */
+struct _store_data
+{
+ void (*func)(const char *,
+ Eeze_Udev_Event,
+ void *,
+ Eeze_Udev_Watch *);
+ void *data;
+ Eeze_Udev_Event event;
+ _udev_monitor *mon;
+ Eeze_Udev_Type type;
+ Eeze_Udev_Watch *watch;
+};
+
+/* private function to further filter watch results based on Eeze_Udev_Type
+ * specified; helpful for new udev versions, but absolutely required for
+ * old udev, which does not implement filtering in device monitors.
+ */
+static Eina_Bool
+_get_syspath_from_watch(void *data,
+ Ecore_Fd_Handler *fd_handler)
+{
+ struct _store_data *store = data;
+ _udev_device *device = NULL, *parent, *tmpdev;
+ const char *ret, *test;
+ Eeze_Udev_Watch_Cb func = store->func;
+ void *sdata = store->data;
+ Eeze_Udev_Watch *watch = store->watch;
+ int event = 0;
+
+ if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
+ return EINA_TRUE;
+
+ device = udev_monitor_receive_device(store->mon);
+
+ if (!device)
+ return EINA_TRUE;
+
+ if ((!(test = udev_device_get_action(device)))
+ || (!(ret = udev_device_get_syspath(device))))
+ goto error;
+
+ if (store->event)
+ {
+ if (!strcmp(test, "add"))
+ {
+ if ((store->event != EEZE_UDEV_EVENT_NONE) &&
+ ((store->event & EEZE_UDEV_EVENT_ADD) != EEZE_UDEV_EVENT_ADD))
+ goto error;
+
+ event |= EEZE_UDEV_EVENT_ADD;
+ }
+ else if (!strcmp(test, "remove"))
+ {
+ if ((store->event != EEZE_UDEV_EVENT_NONE) &&
+ ((store->event & EEZE_UDEV_EVENT_REMOVE) != EEZE_UDEV_EVENT_REMOVE))
+ goto error;
+
+ event |= EEZE_UDEV_EVENT_REMOVE;
+ }
+ else if (!strcmp(test, "change"))
+ {
+ if ((store->event != EEZE_UDEV_EVENT_NONE) &&
+ ((store->event & EEZE_UDEV_EVENT_CHANGE) != EEZE_UDEV_EVENT_CHANGE))
+ goto error;
+
+ event |= EEZE_UDEV_EVENT_CHANGE;
+ }
+ else if (!strcmp(test, "online"))
+ {
+ if ((store->event != EEZE_UDEV_EVENT_NONE) &&
+ ((store->event & EEZE_UDEV_EVENT_ONLINE) != EEZE_UDEV_EVENT_ONLINE))
+ goto error;
+
+ event |= EEZE_UDEV_EVENT_ONLINE;
+ }
+ else
+ {
+ if ((store->event != EEZE_UDEV_EVENT_NONE) &&
+ ((store->event & EEZE_UDEV_EVENT_OFFLINE) != EEZE_UDEV_EVENT_OFFLINE))
+ goto error;
+
+ event |= EEZE_UDEV_EVENT_OFFLINE;
+ }
+ }
+
+ if ((event & EEZE_UDEV_EVENT_OFFLINE) || (event & EEZE_UDEV_EVENT_REMOVE))
+ goto out;
+ switch (store->type)
+ {
+ case EEZE_UDEV_TYPE_KEYBOARD:
+#ifdef OLD_UDEV_RRRRRRRRRRRRRR
+ if ((!(test = udev_device_get_subsystem(device)))
+ || (strcmp(test, "input")))
+ goto error;
+
+ test = udev_device_get_property_value(device, "ID_CLASS");
+
+ if ((_walk_parents_test_attr(device, "bInterfaceProtocol", "01"))
+ || ((test) && (!strcmp(test, "kbd"))))
+ break;
+
+ goto error;
+#endif
+ if ((!udev_device_get_property_value(device, "ID_INPUT_KEYBOARD")) &&
+ (!udev_device_get_property_value(device, "ID_INPUT_KEY")))
+ goto error;
+
+ break;
+
+ case EEZE_UDEV_TYPE_MOUSE:
+#ifdef OLD_UDEV_RRRRRRRRRRRRRR
+ if ((!(test = udev_device_get_subsystem(device)))
+ || (strcmp(test, "input")))
+ goto error;
+
+ test = udev_device_get_property_value(device, "ID_CLASS");
+
+ if ((_walk_parents_test_attr(device, "bInterfaceProtocol", "02"))
+ || ((test) && (!strcmp(test, "mouse"))))
+ break;
+
+ goto error;
+#endif
+
+ if (!udev_device_get_property_value(device, "ID_INPUT_MOUSE"))
+ goto error;
+
+ break;
+
+ case EEZE_UDEV_TYPE_TOUCHPAD:
+#ifdef OLD_UDEV_RRRRRRRRRRRRRR
+ if ((!(test = udev_device_get_subsystem(device)))
+ || (strcmp(test, "input")))
+ goto error;
+
+ if (_walk_parents_test_attr(device, "resolution", NULL))
+ break;
+
+ goto error;
+#endif
+ if (!udev_device_get_property_value(device, "ID_INPUT_TOUCHPAD"))
+ goto error;
+
+ break;
+
+ case EEZE_UDEV_TYPE_JOYSTICK:
+#ifdef OLD_UDEV_RRRRRRRRRRRRRR
+ if ((!(test = udev_device_get_subsystem(device)))
+ || (strcmp(test, "input")))
+ goto error;
+
+ test = udev_device_get_property_value(device, "ID_CLASS");
+
+ if ((test) && (!strcmp(test, "joystick")))
+ break;
+
+ goto error;
+#endif
+ if (!udev_device_get_property_value(device, "ID_INPUT_JOYSTICK"))
+ goto error;
+
+ break;
+
+ case EEZE_UDEV_TYPE_DRIVE_MOUNTABLE:
+#ifdef OLD_UDEV_RRRRRRRRRRRRRR
+ if ((!(test = udev_device_get_subsystem(device)))
+ || (strcmp(test, "block")))
+ goto error;
+#endif
+ if (!(test = (udev_device_get_property_value(device, "ID_FS_USAGE"))) ||
+ (strcmp("filesystem", test)))
+ goto error;
+ {
+ int devcheck;
+
+ devcheck = open(udev_device_get_devnode(device), O_RDONLY);
+ if (devcheck < 0) goto error;
+ close(devcheck);
+ }
+
+ break;
+
+ case EEZE_UDEV_TYPE_DRIVE_INTERNAL:
+ if (udev_device_get_property_value(device, "ID_FS_USAGE")) goto error;
+ test = udev_device_get_sysattr_value(device, "removable");
+ if (test && test[0] == '1') goto error;
+ test = udev_device_get_property_value(device, "ID_BUS");
+ if ((!test) || strcmp(test, "ata")) goto error;
+ test = udev_device_get_property_value(device, "ID_TYPE");
+ if ((!test) || strcmp(test, "disk")) goto error;
+ break;
+
+ case EEZE_UDEV_TYPE_DRIVE_REMOVABLE:
+ if (udev_device_get_sysattr_value(device, "partition")) goto error;
+ test = udev_device_get_sysattr_value(device, "removable");
+ if ((!test) || (test[0] == '0')) goto error;
+ test = udev_device_get_property_value(device, "ID_TYPE");
+ if ((!test) || strcmp(test, "disk")) goto error;
+
+ break;
+
+ case EEZE_UDEV_TYPE_DRIVE_CDROM:
+ if (!udev_device_get_property_value(device, "ID_CDROM"))
+ goto error;
+
+ break;
+
+ case EEZE_UDEV_TYPE_POWER_AC:
+#ifdef OLD_UDEV_RRRRRRRRRRRRRR
+ if ((!(test = udev_device_get_subsystem(device)))
+ || (strcmp(test, "power_supply")))
+ goto error;
+#endif
+ test = udev_device_get_property_value(device, "POWER_SUPPLY_ONLINE");
+ if (!test) goto error;
+ break;
+
+ case EEZE_UDEV_TYPE_POWER_BAT:
+#ifdef OLD_UDEV_RRRRRRRRRRRRRR
+ if ((!(test = udev_device_get_subsystem(device)))
+ || (strcmp(test, "power_supply")))
+ goto error;
+#endif
+ test = udev_device_get_property_value(device, "POWER_SUPPLY_PRESENT");
+ if ((!test) || (strcmp(test, "1"))) goto error;
+ break;
+
+ case EEZE_UDEV_TYPE_NET:
+#ifdef OLD_UDEV_RRRRRRRRRRRRRR
+ if ((!(test = udev_device_get_subsystem(device)))
+ || (strcmp(test, "net")))
+ goto error;
+#endif
+ break;
+
+ case EEZE_UDEV_TYPE_IS_IT_HOT_OR_IS_IT_COLD_SENSOR:
+ {
+ Eina_Bool one, two;
+ const char *t;
+
+#ifdef OLD_UDEV_RRRRRRRRRRRRRR
+ if ((!(test = udev_device_get_subsystem(device)))
+ || (strcmp(test, "hwmon")))
+ goto error;
+#endif /* have to do stuff up here since we need info from the parent */
+ one = _walk_parents_test_attr(device, "temp1_input", NULL);
+ two = _walk_parents_test_attr(device, "temp2_input", NULL);
+ if ((!one) && (!two)) goto error;
+
+ t = one ? "temp1_input" : "temp2_input";
+ /* if device is not the one which has the temp input, we must go up the chain */
+ if (!udev_device_get_sysattr_value(device, t))
+ {
+ for (parent = udev_device_get_parent(device); parent; parent = udev_device_get_parent(parent)) /*check for parent */
+ if (udev_device_get_sysattr_value(parent, t))
+ {
+ tmpdev = device;
+
+ if (!(device = _copy_device(parent)))
+ goto error;
+
+ udev_device_unref(tmpdev);
+ break;
+ }
+ }
+
+ break;
+ }
+ case EEZE_UDEV_TYPE_V4L:
+ if ((!(test = udev_device_get_subsystem(device)))
+ || (strcmp(test, "video4linux")))
+ goto error;
+ break;
+
+ case EEZE_UDEV_TYPE_BLUETOOTH:
+ if ((!(test = udev_device_get_subsystem(device)))
+ || (strcmp(test, "bluetooth")))
+ goto error;
+ break;
+
+ default:
+ break;
+ }
+out:
+ (*func)(eina_stringshare_add(ret), event, sdata, watch);
+error:
+ if (device)
+ udev_device_unref(device);
+ return EINA_TRUE;
+}
+
+EAPI Eeze_Udev_Watch *
+eeze_udev_watch_add(Eeze_Udev_Type type,
+ int event,
+ Eeze_Udev_Watch_Cb cb,
+ void *user_data)
+{
+ _udev_monitor *mon = NULL;
+ int fd;
+ Ecore_Fd_Handler *handler;
+ Eeze_Udev_Watch *watch = NULL;
+ struct _store_data *store = NULL;
+
+ if (!(store = calloc(1, sizeof(struct _store_data))))
+ return NULL;
+
+ if (!(watch = malloc(sizeof(Eeze_Udev_Watch))))
+ goto error;
+
+ if (!(mon = udev_monitor_new_from_netlink(udev, "udev")))
+ goto error;
+
+#ifndef OLD_UDEV_RRRRRRRRRRRRRR
+
+ switch (type)
+ {
+ case EEZE_UDEV_TYPE_JOYSTICK:
+ case EEZE_UDEV_TYPE_KEYBOARD:
+ case EEZE_UDEV_TYPE_MOUSE:
+ case EEZE_UDEV_TYPE_TOUCHPAD:
+ udev_monitor_filter_add_match_subsystem_devtype(mon, "input", NULL);
+ break;
+
+ case EEZE_UDEV_TYPE_DRIVE_MOUNTABLE:
+ case EEZE_UDEV_TYPE_DRIVE_INTERNAL:
+ udev_monitor_filter_add_match_subsystem_devtype(mon, "block", NULL);
+ break;
+
+ case EEZE_UDEV_TYPE_DRIVE_REMOVABLE:
+ case EEZE_UDEV_TYPE_DRIVE_CDROM:
+ break;
+
+ case EEZE_UDEV_TYPE_POWER_AC:
+ case EEZE_UDEV_TYPE_POWER_BAT:
+ udev_monitor_filter_add_match_subsystem_devtype(mon, "power_supply",
+ NULL);
+ break;
+
+ case EEZE_UDEV_TYPE_NET:
+ udev_monitor_filter_add_match_subsystem_devtype(mon, "net", NULL);
+ break;
+
+ case EEZE_UDEV_TYPE_IS_IT_HOT_OR_IS_IT_COLD_SENSOR:
+ udev_monitor_filter_add_match_subsystem_devtype(mon, "hwmon", NULL);
+ break;
+
+ /*
+ case EEZE_UDEV_TYPE_ANDROID:
+ udev_monitor_filter_add_match_subsystem_devtype(mon, "input", "usb_interface");
+ break;
+ */
+
+ case EEZE_UDEV_TYPE_V4L:
+ udev_monitor_filter_add_match_subsystem_devtype(mon, "video4linux",
+ NULL);
+ break;
+
+ case EEZE_UDEV_TYPE_BLUETOOTH:
+ udev_monitor_filter_add_match_subsystem_devtype(mon, "bluetooth",
+ NULL);
+ break;
+
+ default:
+ break;
+ }
+
+#endif
+
+ if (udev_monitor_enable_receiving(mon))
+ goto error;
+
+ fd = udev_monitor_get_fd(mon);
+ store->func = cb;
+ store->data = user_data;
+ store->mon = mon;
+ store->type = type;
+ store->watch = watch;
+ store->event = event;
+
+ if (!(handler = ecore_main_fd_handler_add(fd, ECORE_FD_READ,
+ _get_syspath_from_watch, store, NULL, NULL)))
+ goto error;
+
+ watch->mon = mon;
+ watch->handler = handler;
+ return watch;
+error:
+ if (store)
+ free(store);
+ if (watch)
+ free(watch);
+ if (mon)
+ udev_monitor_unref(mon);
+ ERR("Could not create watch!");
+ return NULL;
+}
+
+EAPI void *
+eeze_udev_watch_del(Eeze_Udev_Watch *watch)
+{
+ struct _store_data *sdata;
+ void *ret = NULL;
+
+ if ((!watch) || (!watch->mon) || (!watch->handler))
+ return NULL;
+
+ sdata = ecore_main_fd_handler_del(watch->handler);
+ udev_monitor_unref(watch->mon);
+
+ if (sdata)
+ {
+ ret = sdata->data;
+ free(sdata);
+ }
+
+ free(watch);
+ return ret;
+}