EFL 1.7 svn doobies
authorraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Thu, 30 Aug 2012 09:54:57 +0000 (09:54 +0000)
committerraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Thu, 30 Aug 2012 09:54:57 +0000 (09:54 +0000)
git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/branches/eeze-1.7@75862 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

60 files changed:
.gitignore [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
TODO [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
doc/Doxyfile.in [new file with mode: 0644]
doc/Makefile.am [new file with mode: 0644]
doc/e.css [new file with mode: 0644]
doc/eeze.dox.in [new file with mode: 0644]
doc/foot.html [new file with mode: 0644]
doc/head.html [new file with mode: 0644]
doc/img/edoxy.css [new file with mode: 0644]
doc/img/eeze.png [new file with mode: 0644]
doc/img/foot_bg.png [new file with mode: 0644]
doc/img/head_bg.png [new file with mode: 0644]
doc/img/header_menu_background.png [new file with mode: 0644]
doc/img/header_menu_background_last.png [new file with mode: 0644]
doc/img/header_menu_current_background.png [new file with mode: 0644]
doc/img/header_menu_unselected_background.png [new file with mode: 0644]
doc/img/logo.png [new file with mode: 0644]
eeze.pc.in [new file with mode: 0644]
eeze.spec.in [new file with mode: 0644]
m4/ac_attribute.m4 [new file with mode: 0644]
m4/efl_binary.m4 [new file with mode: 0644]
m4/efl_compiler_flag.m4 [new file with mode: 0644]
m4/efl_doxygen.m4 [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/bin/Makefile.am [new file with mode: 0644]
src/bin/eeze_disk_ls.c [new file with mode: 0644]
src/bin/eeze_mount.c [new file with mode: 0644]
src/bin/eeze_scanner.c [new file with mode: 0644]
src/bin/eeze_scanner.h [new file with mode: 0644]
src/bin/eeze_udev_test.c [new file with mode: 0644]
src/bin/eeze_umount.c [new file with mode: 0644]
src/lib/Eeze.h [new file with mode: 0644]
src/lib/Eeze_Disk.h [new file with mode: 0644]
src/lib/Eeze_Net.h [new file with mode: 0644]
src/lib/Makefile.am [new file with mode: 0644]
src/lib/eeze_disk.c [new file with mode: 0644]
src/lib/eeze_disk_libmount.c [new file with mode: 0644]
src/lib/eeze_disk_libmount_new.c [new file with mode: 0644]
src/lib/eeze_disk_libmount_old.c [new file with mode: 0644]
src/lib/eeze_disk_mount.c [new file with mode: 0644]
src/lib/eeze_disk_private.h [new file with mode: 0644]
src/lib/eeze_disk_udev.c [new file with mode: 0644]
src/lib/eeze_main.c [new file with mode: 0644]
src/lib/eeze_net.c [new file with mode: 0644]
src/lib/eeze_net_private.h [new file with mode: 0644]
src/lib/eeze_udev_find.c [new file with mode: 0644]
src/lib/eeze_udev_private.c [new file with mode: 0644]
src/lib/eeze_udev_private.h [new file with mode: 0644]
src/lib/eeze_udev_syspath.c [new file with mode: 0644]
src/lib/eeze_udev_walk.c [new file with mode: 0644]
src/lib/eeze_udev_watch.c [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..fc7bc81
--- /dev/null
@@ -0,0 +1,34 @@
+*.o
+*.lo
+*.la
+.deps
+.libs
+Makefile
+Makefile.in
+config.*
+/aclocal.m4
+/autom4te.cache
+/compile
+/configure
+/depcomp
+/eeze.pc
+/eeze.spec
+/install-sh
+/libtool
+/ltmain.sh
+/missing
+/stamp-h1
+/doc/eeze.dox
+/ABOUT-NLS
+/m4/libtool.m4
+/m4/ltoptions.m4
+/m4/ltsugar.m4
+/m4/ltversion.m4
+/m4/lt~obsolete.m4
+/src/bin/eeze_udev_test
+/doc/Doxyfile
+src/bin/eeze_disk_ls
+src/bin/eeze_mount
+src/bin/eeze_scanner
+src/bin/eeze_umount
+
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..96a45af
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,4 @@
+Mike Blumenkrantz (zmike/discomfitor) <michael.blumenkrantz@gmail.com>
+Cedric Bail <cedric@efl.so>
+Mikael Sans <sans.mikael@gmail.com>
+Christophe Dumez <christophe.dumez@intel.com>
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..15bae3b
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,25 @@
+Copyright notice for Eeze:
+
+Copyright (C) 2011 Mike Blumenkrantz and various contributors (see AUTHORS)
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright 
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..6fde511
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,120 @@
+2011-01-29  Carsten Haitzler (The Rasterman)
+
+        1.0.0 release
+
+2011-01-29  Mike Blumenkrantz (discomfitor/zmike)
+
+       * added disk manipulation functions
+       (eeze_disk_function, eeze_disk_new, eeze_disk_new_from_mount, eeze_disk_free, eeze_disk_scan,
+       eeze_disk_data_set, eeze_disk_data_get, eeze_disk_syspath_get, eeze_disk_devpath_get,
+       eeze_disk_fstype_get, eeze_disk_vendor_get, eeze_disk_model_get, eeze_disk_serial_get,
+       eeze_disk_uuid_get, eeze_disk_label_get, eeze_disk_type_get, eeze_disk_removable_get,
+       eeze_disk_mounted_get, eeze_disk_mount, eeze_disk_unmount, eeze_disk_mount_point_get,
+       eeze_disk_mount_point_set, eeze_mount_tabs_watch, eeze_mount_tabs_unwatch,
+       eeze_mount_mtab_scan, eeze_mount_fstab_scan)
+
+2011-02-09  Mike Blumenkrantz (discomfitor/zmike)
+
+       * added handling of mountopts
+        * iso automounting in eeze_mount
+       (EEZE_DISK_MOUNTOPT_UTF8, EEZE_DISK_MOUNTOPT_NOEXEC, EEZE_DISK_MOUNTOPT_NOSUID,
+       EEZE_DISK_MOUNTOPT_REMOUNT, eeze_disk_mountopts_set, eeze_disk_mountopts_get)
+
+2011-03-03  Mike Blumenkrantz (discomfitor/zmike)
+
+       * fixed bug with watches involving filtering being too aggressive for removed/offlined devices
+
+2011-03-12  Mike Blumenkrantz (discomfitor/zmike)
+
+       * added EEZE_UDEV_TYPE_NET
+
+2011-03-12  Mike Blumenkrantz (discomfitor/zmike)
+
+       * added eeze_udev_syspath_get_devname
+
+2011-05-15  Mike Blumenkrantz (discomfitor/zmike)
+
+       * added eeze_disk_cancel, to cancel the current pending mount/umount operation on a disk
+       * added a uid=%i mount option using getuid (NOT geteuid)
+       * added wrapper for mount command exes (such as sudo) with eeze_disk_mount_wrapper_set
+       and eeze_disk_mount_wrapper_get
+       * added functions to perform udev lookups directly on disk devices without wasting
+       unnecessary function calls (eeze_disk_udev_get_parent, eeze_disk_udev_get_property,
+       eeze_disk_udev_get_sysattr, eeze_disk_udev_walk_check_sysattr,
+       eeze_disk_udev_walk_get_sysattr)
+
+2011-05-16  Mike Blumenkrantz (discomfitor/zmike)
+
+       * fixed bug with EEZE_UDEV_TYPE_DRIVE_* detection
+       * fixed eeze_udev_find_unlisted_similar to be less permissive
+       * added EEZE_EVENT_DISK_EJECT and eeze_disk_eject, functions for ejecting a disk
+
+2011-06-29  Mike Blumenkrantz (discomfitor/zmike)
+
+        * fixed bug where EEZE_UDEV_EVENT_NONE would not match all events for watches
+        * fixed segv when detecting removable drives
+        * added eeze_scanner utility daemon
+        * fixed bug where watches would not properly detect disk events
+
+2011-07-15  Cedric Bail
+
+       * added EEZE_UDEV_TYPE_V4L
+
+2011-08-01  Mike Blumenkrantz (discomfitor/zmike)
+
+        * added fix for battery/ac detection with very recent versions of udev
+
+2011-11-17  Mike Blumenkrantz (discomfitor/zmike)
+
+        * added eeze_disk_can_{mount,unmount,eject} to determine at runtime whether eeze
+          is capable of performing disk operations
+
+2011-12-02  Carsten Haitzler (The Rasterman)
+
+        1.1.0 release
+
+2011-12-02  Mike Blumenkrantz (discomfitor/zmike)
+
+        * added network device api (eeze_net_*) and Eeze_Net.h header
+
+2012-01-09  Mikael Sans
+
+       * added EEZE_UDEV_TYPE_BLUETOOTH
+
+2012-04-26 Carsten Haitzler (The Rasterman)
+
+        1.2.0 release
+
+2012-06-11 Mike Blumenkrantz
+
+        * eeze_scanner socket is now readable by anyone
+
+2012-06-12 Mike Blumenkrantz
+
+        * Add fallback mount using device name if a disk has no uuid
+
+2012-06-29 Mike Blumenkrantz
+
+        * Fix crash in eeze_net_free()
+
+2012-06-29 Christophe Dumez (christophe.dumez@intel.com)
+
+        * Added joystick detection
+
+2012-07-10 Mike Blumenkrantz
+
+        * Add a check in event monitoring for disks which ensures that
+          device changes for loopback devices are picked up
+
+2012-07-23 Mike Blumenkrantz
+
+        * Add yet another libmount backend for eeze_disk to handle current
+          setups which do not have mtab and instead use /proc/self/mountinfo
+
+2012-07-30 Mike Blumenkrantz
+
+        * Add EEZE_DISK_MOUNTOPT_NODEV option for disabling device nodes on mount
+
+2012-07-31 Mike Blumenkrantz
+
+        * Prevent mount operations from retrying infinitely on failure
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..7d1c323
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,365 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+
+   Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.  This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+   Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package.  The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.  Some packages provide this
+`INSTALL' file but do not implement all of the features documented
+below.  The lack of an optional feature in a given package is not
+necessarily a bug.  More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+   The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.
+
+     Running `configure' might take a while.  While running, it prints
+     some messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package, generally using the just-built uninstalled binaries.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.  When installing into a prefix owned by root, it is
+     recommended that the package be configured and built as a regular
+     user, and only the `make install' phase executed with root
+     privileges.
+
+  5. Optionally, type `make installcheck' to repeat any self-tests, but
+     this time using the binaries in their final installed location.
+     This target does not install anything.  Running this target as a
+     regular user, particularly if the prior `make install' required
+     root privileges, verifies that the installation completed
+     correctly.
+
+  6. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+  7. Often, you can also type `make uninstall' to remove the installed
+     files again.  In practice, not all packages have tested that
+     uninstallation works correctly, even though it is required by the
+     GNU Coding Standards.
+
+  8. Some packages, particularly those that use Automake, provide `make
+     distcheck', which can by used by developers to test that all other
+     targets like `make install' and `make uninstall' work correctly.
+     This target is generally not run by end users.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you can use GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.  This
+is known as a "VPATH" build.
+
+   With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory.  After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+   On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor.  Like
+this:
+
+     ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CPP="gcc -E" CXXCPP="g++ -E"
+
+   This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
+Installation Names
+==================
+
+   By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc.  You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX', where PREFIX must be an
+absolute file name.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.  In general, the
+default for these options is expressed in terms of `${prefix}', so that
+specifying just `--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+   The most portable way to affect installation locations is to pass the
+correct locations to `configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+`make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+   The first method involves providing an override variable for each
+affected directory.  For example, `make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+`${prefix}'.  Any directories that were specified during `configure',
+but not in terms of `${prefix}', must each be overridden at install
+time for the entire installation to be relocated.  The approach of
+makefile variable overrides for each directory variable is required by
+the GNU Coding Standards, and ideally causes no recompilation.
+However, some platforms have known limitations with the semantics of
+shared libraries that end up requiring recompilation when using this
+method, particularly noticeable in packages that use GNU Libtool.
+
+   The second method involves providing the `DESTDIR' variable.  For
+example, `make install DESTDIR=/alternate/directory' will prepend
+`/alternate/directory' before all installation names.  The approach of
+`DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters.  On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of `${prefix}'
+at `configure' time.
+
+Optional Features
+=================
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+   Some packages offer the ability to configure how verbose the
+execution of `make' will be.  For these packages, running `./configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with `make V=1'; while running `./configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with `make V=0'.
+
+Particular systems
+==================
+
+   On HP-UX, the default C compiler is not ANSI C compatible.  If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+     ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+   On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file.  The option `-nodtk' can be used as
+a workaround.  If GNU CC is not installed, it is therefore recommended
+to try
+
+     ./configure CC="cc"
+
+and if that doesn't work, try
+
+     ./configure CC="cc -nodtk"
+
+   On Solaris, don't put `/usr/ucb' early in your `PATH'.  This
+directory contains several dysfunctional programs; working variants of
+these programs are available in `/usr/bin'.  So, if you need `/usr/ucb'
+in your `PATH', put it _after_ `/usr/bin'.
+
+   On Haiku, software installed for all users goes in `/boot/common',
+not `/usr/local'.  It is recommended to use the following options:
+
+     ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on.  Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS
+     KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+   Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug.  Until the bug is fixed you can use this workaround:
+
+     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+     Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+     Print a summary of the options unique to this package's
+     `configure', and exit.  The `short' variant lists options used
+     only in the top level, while the `recursive' variant lists options
+     also present in any nested packages.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+     Use DIR as the installation prefix.  *note Installation Names::
+     for more details, including other options available for fine-tuning
+     the installation locations.
+
+`--no-create'
+`-n'
+     Run the configure checks, but stop before creating any output
+     files.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..4d9f2c5
--- /dev/null
@@ -0,0 +1,44 @@
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = src doc
+
+MAINTAINERCLEANFILES = \
+Makefile.in \
+aclocal.m4 \
+compile \
+config.guess \
+config.h.in \
+config.h.in~ \
+config.sub \
+configure \
+depcomp \
+install-sh \
+ltconfig \
+ltmain.sh \
+missing \
+eeze*doc*tar* \
+eeze.pc \
+eeze.spec \
+m4/l*
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = eeze.pc
+
+EXTRA_DIST = \
+AUTHORS \
+COPYING \
+README \
+$(pkgconfig_DATA) \
+autogen.sh \
+eeze.pc.in \
+eeze.spec.in \
+eeze.spec \
+m4/efl_doxygen.m4
+
+.PHONY: doc
+
+# Documentation
+
+doc: all
+       @echo "entering doc/"
+       $(MAKE) -C doc doc
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..b953461
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,31 @@
+Eeze 1.7.0
+
+Changes since Eeze 1.2.0:
+-------------------------
+
+Additions:
+
+    * Joystick support
+    * Support for mtab-less systems
+
+Changes since Eeze 1.1.0:
+-------------------------
+
+Additions:
+
+    * Detect bluetooth devices.
+    * Network device API (eeze_net_*).
+
+Changes since Eeze 1.0.0:
+-------------------------
+
+Additions:
+
+    * more disk-related detection/info functions
+    * disk mounting API
+    * eeze_scanner utility for applications to hook for drive detection
+
+Fixes:
+
+    * bugs with device detection related to newer kernel versions
+    * device filtering to be more accurate in some cases
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..e1a5393
--- /dev/null
+++ b/README
@@ -0,0 +1,46 @@
+Eeze 1.7.0
+
+******************************************************************************
+
+ FOR ANY ISSUES PLEASE EMAIL:
+ enlightenment-devel@lists.sourceforge.net
+******************************************************************************
+
+
+Requirements:
+-------------
+
+Must:
+  libc
+  ecore (at least 1.0.0)
+  libudev
+
+Suggested:
+  libmount
+
+Eeze is a library for manipulating devices with an extremely simple api.
+It interfaces directly with device subsystems, avoiding such middleman daemons as
+udisks/upower or hal to immediately gather device information the instant it
+becomes known to the OS.  This can be used to determine such things as:
+  * If a cdrom has a disk inserted
+  * The temperature of a cpu core
+  * The remaining power left in a battery
+  * The current power consumption of various parts
+  * 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.
+
+Eeze 1.1 adds more detailed disk detection as well as filesystem mount point manipulation.
+Using a combination of udev and mount, it is possible to easily write disk-based mount services
+which do not rely on any external processes or libraries aside from Eeze.
+------------------------------------------------------------------------------
+COMPILING AND INSTALLING:
+
+  ./configure
+  make
+(as root unless you are installing in your users directories):
+  make install
+      
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..a31b4aa
--- /dev/null
+++ b/TODO
@@ -0,0 +1,9 @@
+udev:  switch enum to bitmasks with categories probably
+       documentation for all types
+       more functions or something?
+
+TO BE ADDED
+automounter
+libdevinfo for solaris
+???
+Profit
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..00116ea
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+rm -rf autom4te.cache
+rm -f aclocal.m4 ltmain.sh
+
+touch README
+touch ABOUT-NLS
+
+echo "Running aclocal..." ; aclocal $ACLOCAL_FLAGS -I m4 || exit 1
+echo "Running autoheader..." ; autoheader || exit 1
+echo "Running autoconf..." ; autoconf || exit 1
+echo "Running libtoolize..." ; (libtoolize --copy --automake || glibtoolize --automake) || exit 1
+echo "Running automake..." ; automake --add-missing --copy --gnu || exit 1
+
+W=0
+
+rm -f config.cache-env.tmp
+echo "OLD_PARM=\"$@\"" >> config.cache-env.tmp
+echo "OLD_CFLAGS=\"$CFLAGS\"" >> config.cache-env.tmp
+echo "OLD_PATH=\"$PATH\"" >> config.cache-env.tmp
+echo "OLD_PKG_CONFIG_PATH=\"$PKG_CONFIG_PATH\"" >> config.cache-env.tmp
+echo "OLD_LDFLAGS=\"$LDFLAGS\"" >> config.cache-env.tmp
+
+cmp config.cache-env.tmp config.cache-env >> /dev/null
+if [ $? -ne 0 ]; then
+       W=1;
+fi
+
+if [ $W -ne 0 ]; then
+       echo "Cleaning configure cache...";
+       rm -f config.cache config.cache-env
+       mv config.cache-env.tmp config.cache-env
+else
+       rm -f config.cache-env.tmp
+fi
+
+if [ -z "$NOCONFIGURE" ]; then
+       ./configure -C "$@"
+fi
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..5569970
--- /dev/null
@@ -0,0 +1,294 @@
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+m4_define([v_maj], [1])
+m4_define([v_min], [7])
+m4_define([v_mic], [0])
+m4_define([v_rev], m4_esyscmd([(svnversion "${SVN_REPO_PATH:-.}" | grep -v '\(export\|Unversioned directory\)' || echo 0) | awk -F : '{printf("%s\n", $1);}' | tr -d ' :MSP\n']))
+m4_if(v_rev, [0], [m4_define([v_rev], m4_esyscmd([git log 2> /dev/null | (grep -m1 git-svn-id || echo 0) | sed -e 's/.*@\([0-9]*\).*/\1/' | tr -d '\n']))])
+##--   When released, remove the dnl on the below line
+m4_undefine([v_rev])
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+m4_ifdef([v_rev], [m4_define([v_ver], [v_maj.v_min.v_mic.v_rev])], [m4_define([v_ver], [v_maj.v_min.v_mic])])
+m4_define([lt_cur], m4_eval(v_maj + v_min))
+m4_define([lt_rev], v_mic)
+m4_define([lt_age], v_min)
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+
+AC_INIT([eeze], [v_ver], [enlightenment-devel@lists.sourceforge.net])
+AC_PREREQ([2.52])
+AC_CONFIG_SRCDIR([configure.ac])
+AC_CONFIG_MACRO_DIR([m4])
+
+AC_CONFIG_HEADERS([config.h])
+AH_TOP([
+#ifndef EFL_CONFIG_H__
+#define EFL_CONFIG_H__
+])
+AH_BOTTOM([
+#endif /* EFL_CONFIG_H__ */
+])
+
+AM_INIT_AUTOMAKE([1.6 dist-bzip2])
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl
+define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl
+AC_PROG_LIBTOOL
+
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+m4_ifdef([v_rev], , [m4_define([v_rev], [0])])
+m4_ifdef([v_rel], , [m4_define([v_rel], [])])
+AC_DEFINE_UNQUOTED(VMAJ, [v_maj], [Major version])
+AC_DEFINE_UNQUOTED(VMIN, [v_min], [Minor version])
+AC_DEFINE_UNQUOTED(VMIC, [v_mic], [Micro version])
+AC_DEFINE_UNQUOTED(VREV, [v_rev], [Revison])
+version_info="lt_cur:lt_rev:lt_age"
+release_info="v_rel"
+AC_SUBST(version_info)
+AC_SUBST(release_info)
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+VMAJ=v_maj
+AC_SUBST(VMAJ)
+
+### Needed information
+
+AC_CANONICAL_BUILD
+AC_CANONICAL_HOST
+
+requirement_eeze="ecore >= 1.6.99 eina >= 1.6.99 libudev"
+
+
+### Checks for programs
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_C___ATTRIBUTE__
+
+# pkg-config
+PKG_PROG_PKG_CONFIG
+
+# Check whether pkg-config supports Requires.private
+AS_IF(
+   [$PKG_CONFIG --atleast-pkgconfig-version 0.22],
+      [pkgconfig_requires_private="Requires.private"],
+   [pkgconfig_requires_private="Requires"]
+)
+AC_SUBST(pkgconfig_requires_private)
+
+# doxygen program for documentation building
+
+EFL_CHECK_DOXYGEN([build_doc="yes"], [build_doc="no"])
+
+
+### Checks for libraries
+
+PKG_CHECK_MODULES([EEZE], [${requirement_eeze}])
+
+udev_version=$(pkg-config libudev --modversion)
+
+if test $udev_version -lt 143;then
+  AC_MSG_ERROR([udev version is too old!])
+elif test $udev_version -lt 148;then
+  AC_MSG_WARN([Old udev version detected, enabling compat code])
+  AC_DEFINE([OLD_UDEV_RRRRRRRRRRRRRR],[1],[compat functionality for udev < 148])
+fi
+
+eeze_mount=
+PKG_CHECK_EXISTS([mount >= 2.18.0],
+  [
+     AC_DEFINE([HAVE_EEZE_MOUNT], [1], [Eeze is mount-capable])
+     AM_CONDITIONAL([HAVE_EEZE_MOUNT], [true])
+     eeze_mount="yes"
+  ],
+  AM_CONDITIONAL([HAVE_EEZE_MOUNT], [false])
+)
+
+if test "x$eeze_mount" = "xyes";then
+  AC_ARG_WITH([mount], [AS_HELP_STRING([--with-mount], [specify mount bin @<:@default=detect@:>@])], [with_mount=$withval], [with_mount="detect"])
+  AC_ARG_WITH([umount], [AS_HELP_STRING([--with-umount], [specify umount bin @<:@default=detect@:>@])], [with_umount=$withval], [with_umount="detect"])
+  AC_ARG_WITH([eject], [AS_HELP_STRING([--with-eject], [specify eject bin @<:@default=detect@:>@])], [with_eject=$withval], [with_eject="detect"])
+  PKG_CHECK_MODULES([LIBMOUNT], [mount >= 2.18.0])
+  mount_v=$(pkg-config --modversion mount)
+  PKG_CHECK_MODULES([ECORE_FILE], [ecore-file >= 1.6.99])
+  PKG_CHECK_MODULES([EET], [eet >= 1.6.99])
+  PKG_CHECK_MODULES([ECORE_CON], [ecore-con >= 1.6.99])
+
+  if test "x$with_mount" = "xdetect";then
+    AC_PATH_PROG([with_mount], [mount], [])
+  fi
+  if test -z "$with_mount" ; then
+    AC_DEFINE_UNQUOTED([MOUNTABLE], [0], [whether mount is available])
+  else
+    AC_DEFINE_UNQUOTED([MOUNTABLE], [1], [whether mount is available])
+  fi
+  AC_DEFINE_UNQUOTED([EEZE_MOUNT_BIN], ["$with_mount"], [mount bin to use])
+
+  if test "x$with_umount" = "xdetect";then
+    AC_PATH_PROG([with_umount], [umount], [])
+  fi
+  if test -z "$with_umount" ; then
+    AC_DEFINE_UNQUOTED([UNMOUNTABLE], [0], [whether umount is available])
+  else
+    AC_DEFINE_UNQUOTED([UNMOUNTABLE], [1], [whether umount is available])
+  fi
+  AC_DEFINE_UNQUOTED([EEZE_UNMOUNT_BIN], ["$with_umount"], [umount bin to use])
+
+  if test "x$with_eject" = "xdetect";then
+    AC_PATH_PROG([with_eject], [eject], [])
+  fi
+  if test -z "$with_eject" ; then
+    AC_DEFINE_UNQUOTED([EJECTABLE], [0], [whether eject is available])
+  else
+    AC_DEFINE_UNQUOTED([EJECTABLE], [1], [whether eject is available])
+  fi
+  AC_DEFINE_UNQUOTED([EEZE_EJECT_BIN], ["$with_eject"], [eject bin to use])
+fi
+
+want_mtab=
+AC_ARG_ENABLE([mtab],
+   [AC_HELP_STRING([--enable-mtab],
+       [force use of mtab for mount info @<:@default=detect@:>@])],
+   [
+    if test "x${enableval}" = "xyes" ; then
+       want_mtab="yes"
+    else
+       want_mtab="no"
+    fi],
+   [want_mtab="auto"])
+
+
+if test "x${want_mtab}" = "xyes" ; then
+  AM_CONDITIONAL([OLD_LIBMOUNT], [false])
+  AM_CONDITIONAL([NEW_LIBMOUNT], [false])
+else
+  if test -n "$mount_v";then
+    AM_CONDITIONAL([OLD_LIBMOUNT], [test "$(echo $mount_v | cut -d'.' -f2)" -lt 19])
+    AM_CONDITIONAL([NEW_LIBMOUNT], [test "$(echo $mount_v | cut -d'.' -f2)" -gt 19])
+  else
+    AM_CONDITIONAL([OLD_LIBMOUNT], [false])
+    AM_CONDITIONAL([NEW_LIBMOUNT], [false])
+  fi
+fi
+AM_COND_IF([OLD_LIBMOUNT], [
+     AC_DEFINE_UNQUOTED([OLD_LIBMOUNT], [1], [using first version of libmount])
+  ],[])
+
+AC_CHECK_HEADERS([netinet/in.h])
+want_ipv6="yes"
+have_ipv6="no"
+
+AC_ARG_ENABLE([ipv6],
+   [AC_HELP_STRING([--disable-ipv6],
+       [disable ipv6 functionality @<:@default=detect@:>@])],
+   [
+    if test "x${enableval}" = "xyes" ; then
+       want_ipv6="yes"
+    else
+       want_ipv6="no"
+    fi],
+   [want_ipv6="auto"])
+
+# Verify IPV6 availability in headers
+if test "x${want_ipv6}" != "xno" ; then
+   AC_CHECK_TYPES([struct ipv6_mreq],
+      [have_ipv6="yes"],
+      [have_ipv6="no"],
+      [[
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+      ]])
+fi
+
+if test "x${have_ipv6}" = "xyes" ; then
+   AC_DEFINE(HAVE_IPV6, 1, [Define if IPV6 is supported])
+fi
+
+### Checks for header files
+
+
+### Checks for types
+
+
+### Checks for structures
+
+
+### Checks for compiler characteristics
+
+AC_HEADER_STDC
+
+if ! test "x${VMIC}" = "x" ; then
+   EFL_COMPILER_FLAG([-Wall])
+   EFL_COMPILER_FLAG([-W])
+fi
+
+EFL_COMPILER_FLAG([-Wshadow])
+
+
+### Binary
+
+EFL_ENABLE_BIN([eeze-udev-test], ["yes"])
+EFL_ENABLE_BIN([eeze-mount], ["yes"])
+EFL_ENABLE_BIN([eeze-disk-ls], ["yes"])
+EFL_ENABLE_BIN([eeze-umount], ["yes"])
+EFL_ENABLE_BIN([eeze-scanner], ["yes"])
+
+AC_SUBST(requirement_eeze)
+
+
+AC_OUTPUT([
+Makefile
+doc/eeze.dox
+doc/Makefile
+doc/Doxyfile
+src/Makefile
+src/lib/Makefile
+src/bin/Makefile
+eeze.pc
+eeze.spec
+])
+
+
+#####################################################################
+## Info
+
+echo
+echo
+echo
+echo "------------------------------------------------------------------------"
+echo "$PACKAGE $VERSION"
+echo "------------------------------------------------------------------------"
+echo
+echo "Configuration Options Summary:"
+if test "x$eeze_mount" = "xyes";then
+  echo
+  echo "Mount..................: ${with_mount}"
+  echo "Umount.................: ${with_umount}"
+  echo "Eject..................: ${with_eject}"
+  echo
+fi
+echo "Tests..................: ${have_eeze_udev_test}"
+echo
+echo "Demos..................:"
+echo "  eeze_mount...........: ${have_eeze_mount}"
+echo "  eeze_umount..........: ${have_eeze_umount}"
+echo "  eeze_disk_ls.........: ${have_eeze_disk_ls}"
+echo
+echo "Utilities..............:"
+echo "  eeze_scanner.........: ${have_eeze_scanner}"
+echo
+echo "IPv6...................: ${have_ipv6}"
+echo
+echo "Documentation..........: ${build_doc}"
+echo
+echo "Compilation............: make (or gmake)"
+echo "  CPPFLAGS.............: $CPPFLAGS"
+echo "  CFLAGS...............: $CFLAGS"
+echo "  LDFLAGS..............: $LDFLAGS"
+echo
+echo "Installation...........: make install (as root if needed, with 'su' or 'sudo')"
+echo "  prefix...............: $prefix"
+echo
+
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
new file mode 100644 (file)
index 0000000..da43f44
--- /dev/null
@@ -0,0 +1,139 @@
+ALIASES                = 
+ALLEXTERNALS           = NO
+ALPHABETICAL_INDEX     = YES
+ALWAYS_DETAILED_SEC    = NO
+BINARY_TOC             = NO
+BRIEF_MEMBER_DESC      = YES
+CASE_SENSE_NAMES       = YES
+CHM_FILE               = 
+CLASS_DIAGRAMS         = NO
+CLASS_GRAPH            = NO
+COLLABORATION_GRAPH    = NO
+COLS_IN_ALPHA_INDEX    = 2
+COMPACT_LATEX          = NO
+COMPACT_RTF            = NO
+DISABLE_INDEX          = YES
+DISTRIBUTE_GROUP_DOC   = NO
+DOT_CLEANUP            = YES
+DOTFILE_DIRS           = 
+DOT_GRAPH_MAX_NODES    = 50
+DOT_IMAGE_FORMAT       = png
+DOT_PATH               = 
+ENABLED_SECTIONS       = 
+ENABLE_PREPROCESSING   = YES
+ENUM_VALUES_PER_LINE   = 1
+EXAMPLE_PATH           = 
+EXAMPLE_PATTERNS       = 
+EXAMPLE_RECURSIVE      = NO
+EXCLUDE                = 
+EXCLUDE_PATTERNS       = 
+EXCLUDE_SYMLINKS       = NO
+EXPAND_AS_DEFINED      = 
+EXPAND_ONLY_PREDEF     = NO
+EXTERNAL_GROUPS        = YES
+EXTRACT_ALL            = NO
+EXTRACT_LOCAL_CLASSES  = NO
+EXTRACT_PRIVATE        = NO
+EXTRACT_STATIC         = NO
+EXTRA_PACKAGES         = 
+FILE_PATTERNS          =
+FILTER_SOURCE_FILES    = NO
+FULL_PATH_NAMES        = NO
+GENERATE_AUTOGEN_DEF   = NO
+GENERATE_BUGLIST       = YES
+GENERATE_CHI           = NO
+GENERATE_DEPRECATEDLIST= YES
+GENERATE_HTMLHELP      = NO
+GENERATE_HTML          = YES
+GENERATE_LATEX         = YES
+GENERATE_LEGEND        = YES
+GENERATE_MAN           = YES
+GENERATE_RTF           = NO
+GENERATE_TAGFILE       = 
+GENERATE_TESTLIST      = YES
+GENERATE_TODOLIST      = YES
+GENERATE_TREEVIEW      = NO
+GENERATE_XML           = NO
+GRAPHICAL_HIERARCHY    = NO
+HAVE_DOT               = NO
+HHC_LOCATION           = 
+HIDE_FRIEND_COMPOUNDS  = YES
+HIDE_SCOPE_NAMES       = NO
+HIDE_UNDOC_CLASSES     = YES
+HIDE_UNDOC_MEMBERS     = YES
+HIDE_UNDOC_RELATIONS   = YES
+HTML_ALIGN_MEMBERS     = YES
+HTML_FILE_EXTENSION    = .html
+HTML_FOOTER            = @srcdir@/foot.html
+HTML_HEADER            = @srcdir@/head.html
+HTML_OUTPUT            = html
+HTML_STYLESHEET        = @srcdir@/e.css
+IGNORE_PREFIX          = 
+IMAGE_PATH             = img
+INCLUDED_BY_GRAPH      = NO
+INCLUDE_FILE_PATTERNS  = 
+INCLUDE_GRAPH          = NO
+INCLUDE_PATH           =
+INHERIT_DOCS           = YES
+INLINE_INFO            = YES
+INLINE_INHERITED_MEMB  = NO
+INLINE_SOURCES         = NO
+INPUT                  = @srcdir@/eeze.dox @top_srcdir@/src/lib
+INPUT_FILTER           = 
+INTERNAL_DOCS          = NO
+JAVADOC_AUTOBRIEF      = YES
+LATEX_BATCHMODE        = NO
+LATEX_CMD_NAME         = latex
+LATEX_HEADER           = 
+LATEX_OUTPUT           = latex
+MACRO_EXPANSION        = NO
+MAKEINDEX_CMD_NAME     = makeindex
+MAN_EXTENSION          = .3
+MAN_LINKS              = YES
+MAN_OUTPUT             = man
+MAX_INITIALIZER_LINES  = 30
+MULTILINE_CPP_IS_BRIEF = NO
+OPTIMIZE_OUTPUT_FOR_C  = YES
+OPTIMIZE_OUTPUT_JAVA   = NO
+OUTPUT_DIRECTORY       = .
+OUTPUT_LANGUAGE        = English
+PAPER_TYPE             = a4wide
+PDF_HYPERLINKS         = YES
+PERL_PATH              = /usr/bin/perl
+PREDEFINED             = 
+PROJECT_NAME           = Eeze
+PROJECT_NUMBER         =
+QUIET                  = NO
+RECURSIVE              = YES
+REFERENCES_LINK_SOURCE = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION    = YES
+REPEAT_BRIEF           = YES
+RTF_EXTENSIONS_FILE    = 
+RTF_HYPERLINKS         = NO
+RTF_OUTPUT             = rtf
+RTF_STYLESHEET_FILE    = 
+SEARCHENGINE           = NO
+SEARCH_INCLUDES        = YES
+SHORT_NAMES            = NO
+SHOW_INCLUDE_FILES     = NO
+SHOW_USED_FILES        = NO
+SKIP_FUNCTION_MACROS   = YES
+SORT_MEMBER_DOCS       = YES
+SOURCE_BROWSER         = NO
+STRIP_CODE_COMMENTS    = YES
+STRIP_FROM_PATH        = src/
+SUBGROUPING            = YES
+TAB_SIZE               = 2
+TAGFILES               = 
+TEMPLATE_RELATIONS     = NO
+TOC_EXPAND             = NO
+TREEVIEW_WIDTH         = 250
+USE_PDFLATEX           = NO
+VERBATIM_HEADERS       = NO
+WARN_FORMAT            = "$file:$line: $text"
+WARN_IF_UNDOCUMENTED   = YES
+WARNINGS               = YES
+WARN_LOGFILE           = 
+XML_DTD                = 
+XML_SCHEMA             = 
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644 (file)
index 0000000..fefb763
--- /dev/null
@@ -0,0 +1,33 @@
+MAINTAINERCLEANFILES = Makefile.in eeze.dox
+
+.PHONY: doc
+
+PACKAGE_DOCNAME = $(PACKAGE_TARNAME)-$(PACKAGE_VERSION)-doc
+
+if EFL_BUILD_DOC
+
+doc-clean:
+       rm -rf html/ latex/ man/ xml/ $(top_builddir)/$(PACKAGE_DOCNAME).tar*
+
+doc: all doc-clean
+       $(efl_doxygen)
+       cp $(srcdir)/img/* html/
+       cp $(srcdir)/img/* latex/
+       rm -rf $(PACKAGE_DOCNAME).tar*
+       mkdir -p $(PACKAGE_DOCNAME)/doc
+       cp -R html/ latex/ man/ $(PACKAGE_DOCNAME)/doc
+       tar cf $(PACKAGE_DOCNAME).tar $(PACKAGE_DOCNAME)/
+       bzip2 -9 $(PACKAGE_DOCNAME).tar
+       rm -rf $(PACKAGE_DOCNAME)/
+       mv $(PACKAGE_DOCNAME).tar.bz2 $(top_builddir)
+
+clean-local: doc-clean
+
+else
+
+doc:
+       @echo "Documentation not built. Run ./configure --help"
+
+endif
+
+EXTRA_DIST = Doxyfile.in $(wildcard $(srcdir)img/*.*) e.css head.html foot.html eeze.dox.in
diff --git a/doc/e.css b/doc/e.css
new file mode 100644 (file)
index 0000000..2dd6b44
--- /dev/null
+++ b/doc/e.css
@@ -0,0 +1,273 @@
+/*
+    Author:
+        Andres Blanc <andresblanc@gmail.com>
+       DaveMDS Andreoli <dave@gurumeditation.it>
+
+    Supported Browsers:
+        ie7, opera9, konqueror4 and firefox3
+
+        Please use a different file for ie6, ie5, etc. hacks.
+*/
+
+
+/* Necessary to place the footer at the bottom of the page */
+html, body {
+       height: 100%;
+       margin: 0px;
+       padding: 0px;
+}
+
+#container {
+       min-height: 100%;
+       height: auto !important;
+       height: 100%;
+       margin: 0 auto -53px;
+}
+
+#footer, #push {
+       height: 53px;
+}
+
+
+* html #container {
+       height: 100%;
+}
+
+/* Prevent floating elements overflowing containers */
+.clear {
+       clear: both;
+       width: 0px;
+       height: 0px;
+}
+
+/* Flexible & centered layout from 750 to 960 pixels */
+.layout {
+       max-width: 960px;
+       min-width: 760px;
+       margin-left: auto;
+       margin-right: auto;
+}
+
+body {
+       /*font-family: Lucida Grande, Helvetica, sans-serif;*/
+       font-family: "Bitstream Vera","Vera","Trebuchet MS",Trebuchet,Tahoma,sans-serif
+}
+
+/* Prevent design overflowing the viewport in small resolutions */
+#container {
+       padding-right: 17px;
+       padding-left: 17px;
+       background-image: url(head_bg.png);
+       background-repeat: repeat-x;
+}
+
+/****************************/
+/* Top main menu            */
+/****************************/
+#header_logo {
+   background-image        : url(logo.png);
+   width                   : 61px;
+}
+
+#header_logo a {
+   position                : absolute;
+   border                  : 0px;
+   background-color        : transparent;
+   top                     : 0px;
+   width                   : 60px;
+   height                  : 60px;
+}
+
+#header_menu {
+   background-image        : url(header_menu_background.png);
+   font                    : normal 10pt verdana,'Bitstream Vera Sans',helvetica,arial,sans-serif;
+   text-align              : right;
+}
+
+#header_last {
+   background-image        : url(header_menu_background_last.png);
+   width                   : 15px;
+}
+
+td.nav_passive {
+   background              : url(header_menu_unselected_background.png) 0 0 no-repeat;
+   height                  : 63px;
+   font-family             : "Bitstream Vera","Vera","Trebuchet MS",Trebuchet,Tahoma,sans-serif;
+   font-size               : 11px;
+   padding                 : 20px 10px 20px 10px;
+   vertical-align          : middle;
+}
+
+td.nav_active {
+   background              : url(header_menu_current_background.png) 0 0 no-repeat;
+   height                  : 63px;
+   color                   : #646464;
+   font-family             : "Bitstream Vera","Vera","Trebuchet MS",Trebuchet,Tahoma,sans-serif;
+   font-size               : 11px;
+   font-weight             : bold;
+   padding                 : 20px 10px 20px 10px;
+   vertical-align          : middle;
+}
+
+#header_menu a {
+   display                 : block;
+   text-decoration         : none;
+   cursor                  : pointer;
+   color                   : #cdcdcd;
+}
+
+
+
+#header {
+       width: 100%;
+       height: 102px;
+}
+
+#header h1 {
+       width: 63px;
+       height: 63px;
+       position: absolute;
+       margin: 0px;
+}
+
+#header h1 span {
+       display: none;
+}
+
+#header h2 {
+       display: none;
+}
+
+/* .menu-container is used to set properties common to .menu and .submenu */
+#header .menu-container {
+}
+
+#header .menu-container ul {
+       list-style-type: none;
+       list-style-position: inside;
+       margin: 0;
+}
+
+#header .menu-container li {
+       display: block;
+       float: right;
+}
+
+#header .menu {
+       height: 63px;
+       display: block;
+       background-image: url(menu_bg.png);
+       background-repeat: repeat-x;
+}
+
+#header .menu ul {
+       height: 100%;
+       display: block;
+       background-image: url(menu_bg_last.png);
+       background-repeat: no-repeat;
+       background-position: top right;
+       padding-right: 17px;
+}
+
+#header .menu li {
+       height: 100%;
+       text-align: center;
+       background-image: url(menu_bg_unsel.png);
+       background-repeat: no-repeat;
+}
+
+#header .menu a {
+       height: 100%;
+       display: block;
+       color: #cdcdcd;
+       text-decoration: none;
+       font-size: 10pt;
+       line-height: 59px;
+       text-align: center;
+       padding: 0px 15px 0px 15px;
+}
+
+#header .menu li:hover {
+       background-image: url(menu_bg_hover.png);
+       background-repeat: no-repeat;
+}
+
+#header .menu li:hover a {
+       color: #FFFFFF;
+}
+
+#header .menu li.current {
+       background-image: url(menu_bg_current.png);
+       background-repeat: no-repeat;
+}
+
+#header .menu li.current a {
+       color: #646464;
+}
+
+
+/* Hide all the submenus but the current */
+#header .submenu ul {
+       display: none;
+}
+
+#header .submenu .current {
+       display: block;
+}
+
+#header .submenu {
+       font: bold 10px verdana,'Bitstream Vera Sans',helvetica,arial,sans-serif;
+       margin-top: 10px;
+}
+
+#header .submenu a {
+       color: #888888;
+       text-decoration: none;
+       font-size: 0.9em;
+       line-height: 15px;
+       padding:0px 5px 0px 5px;
+}
+
+#header .submenu a:hover {
+       color: #444444;
+}
+
+#header .submenu li {
+       border-left: 1px solid #DDDDDD;
+}
+
+#header .submenu li:last-child {
+       border-left: 0;
+}
+
+#header .doxytitle {
+       position: absolute;
+       font-size: 1.8em;
+       font-weight: bold;
+       color: #444444;
+       line-height: 35px;
+}
+
+#header small {
+       font-size: 0.4em;
+}
+
+#footer {
+       background-image: url(foot_bg.png);
+       width: 100%;
+}
+
+#footer table {
+       width: 100%;
+       text-align: center;
+       white-space: nowrap;
+       padding: 5px 30px 5px 30px;
+       font-size: 0.8em;
+       font-family: "Bitstream Vera","Vera","Trebuchet MS",Trebuchet,Tahoma,sans-serif;
+       color: #888888;
+}
+
+#footer td.copyright {
+       width: 100%;
+}
+
diff --git a/doc/eeze.dox.in b/doc/eeze.dox.in
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/doc/foot.html b/doc/foot.html
new file mode 100644 (file)
index 0000000..d43cf8f
--- /dev/null
@@ -0,0 +1,18 @@
+ <div id="push"></div>
+ </div> <!-- #content -->
+  </div> <!-- .layout -->
+ </div> <!-- #container -->
+  <div id="footer">
+    <table><tr>
+      <td class="copyright">Copyright &copy;$year Enlightenment</td>
+      <td class="generated">Docs generated $datetime</td>
+    </tr></table>
+  </div>
+
+
+</body>
+</html>
diff --git a/doc/head.html b/doc/head.html
new file mode 100644 (file)
index 0000000..2d9ea92
--- /dev/null
@@ -0,0 +1,68 @@
+<html>
+<head>
+    <title>$title</title>
+    <meta http-equiv="content-type" content="text/html;charset=UTF-8">
+    <meta name="author" content="Andres Blanc" >
+    
+    <link rel="icon" href="img/favicon.png" type="image/x-icon">
+    <link rel="shortcut icon" href="img/favicon.png" type="image/x-icon">
+    <link rel="icon" href="img/favicon.png" type="image/ico">
+    <link rel="shortcut icon" href="img/favicon.png" type="image/ico">
+
+    <link rel="stylesheet" type="text/css" href="e.css">
+    <link rel="stylesheet" type="text/css" href="edoxy.css">
+</head>
+
+<body>
+
+<div id="container">
+
+<div id="header">
+<div class="layout">
+    
+    <h1><span>Enlightenment</span></h1>
+    <h2><span>Beauty at your fingertips</span></h2>
+
+    <table cellspacing="0" cellpadding="0" width="100%"><tr>
+      <td id="header_logo">
+        <a href="http://www.enlightenment.org"></a>
+      </td>
+      <td id="header_menu">
+        <table cellspacing="0" cellpadding="0" align="right"><tr>
+          <td class="nav_passive"><a class="nav_passive" href="http://www.enlightenment.org/p.php?p=home">Home</a></td> 
+          <td class="nav_passive"><a class="nav_passive" href="http://www.enlightenment.org/p.php?p=news">News</a></td> 
+          <td class="nav_passive"><a class="nav_passive" href="http://www.enlightenment.org/p.php?p=about">About</a></td> 
+          <td class="nav_passive"><a class="nav_passive" href="http://www.enlightenment.org/p.php?p=download">Download</a></td> 
+          <td class="nav_passive"><a class="nav_passive" href="http://www.enlightenment.org/p.php?p=support">Support</a></td> 
+          <td class="nav_passive"><a class="nav_passive" href="http://www.enlightenment.org/p.php?p=contribute">Contribute</a></td> 
+          <td class="nav_passive"><a class="nav_passive" href="http://www.enlightenment.org/p.php?p=contact">Contact</a></td> 
+          <td class="nav_passive"><a class="nav_passive" href="http://trac.enlightenment.org/e">Tracker</a></td>
+          <td class="nav_passive"><a class="nav_passive" href="http://www.enlightenment.org/p.php?p=docs">Docs</a></td> 
+        </tr></table>          
+      </td>
+      <td id="header_last"></td>
+    </tr></table>
+
+    <div class="doxytitle">
+        $projectname Documentation <small>at $date</small>
+    </div>
+
+    <div class="menu-container">
+        <div class="submenu">
+            <ul class="current">
+                <li><a href="files.html">Files</a></li>
+                <li><a href="globals.html">Globals</a></li>
+                <li><a href="Eeze_8h.html">API Reference</a></li>
+                <li><a href="modules.html">Modules</a></li>
+               <li class="current"><a  href="index.html">Main Page</a></li>
+            </ul>
+        </div>
+    </div>
+
+
+    <div class="clear"></div>
+</div>
+</div>
+
+<div id="content">
+<div class="layout">
diff --git a/doc/img/edoxy.css b/doc/img/edoxy.css
new file mode 100644 (file)
index 0000000..311ca23
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+ * This file contain a custom doxygen style to match e.org graphics
+ */
+
+
+
+/* BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
+       font-family: Geneva, Arial, Helvetica, sans-serif;
+}*/ 
+BODY, TD {
+       font-size: 12px;
+}
+H1 {
+       text-align: center;
+       font-size: 160%;
+}
+H2 {
+       font-size: 120%;
+}
+H3 {
+       font-size: 100%;
+}
+CAPTION { 
+       font-weight: bold 
+}
+DIV.qindex {
+       width: 100%;
+       background-color: #e8eef2;
+       border: 1px solid #84b0c7;
+       text-align: center;
+       margin: 2px;
+       padding: 2px;
+       line-height: 140%;
+}
+DIV.navpath {
+       width: 100%;
+       background-color: #e8eef2;
+       border: 1px solid #84b0c7;
+       text-align: center;
+       margin: 2px;
+       padding: 2px;
+       line-height: 140%;
+}
+DIV.navtab {
+       background-color: #e8eef2;
+       border: 1px solid #84b0c7;
+       text-align: center;
+       margin: 2px;
+       margin-right: 15px;
+       padding: 2px;
+}
+TD.navtab {
+       font-size: 70%;
+}
+A.qindex {
+       text-decoration: none;
+       font-weight: bold;
+       color: #1A419D;
+}
+A.qindex:visited {
+       text-decoration: none;
+       font-weight: bold;
+       color: #1A419D
+}
+A.qindex:hover {
+       text-decoration: none;
+       background-color: #ddddff;
+}
+A.qindexHL {
+       text-decoration: none;
+       font-weight: bold;
+       background-color: #6666cc;
+       color: #ffffff;
+       border: 1px double #9295C2;
+}
+A.qindexHL:hover {
+       text-decoration: none;
+       background-color: #6666cc;
+       color: #ffffff;
+}
+A.qindexHL:visited { 
+       text-decoration: none; 
+       background-color: #6666cc; 
+       color: #ffffff 
+}
+A.el { 
+       text-decoration: none; 
+       font-weight: bold 
+}
+A.elRef { 
+       font-weight: bold 
+}
+A.code:link { 
+       text-decoration: none; 
+       font-weight: normal; 
+       color: #0000FF
+}
+A.code:visited { 
+       text-decoration: none; 
+       font-weight: normal; 
+       color: #0000FF
+}
+A.codeRef:link { 
+       font-weight: normal; 
+       color: #0000FF
+}
+A.codeRef:visited { 
+       font-weight: normal; 
+       color: #0000FF
+}
+A:hover, A:visited:hover { 
+       text-decoration: none;  
+       /* background-color: #f2f2ff; */
+       color: #000055;
+}
+A.anchor {
+       color: #000;
+}
+DL.el { 
+       margin-left: -1cm 
+}
+.fragment {
+       font-family: monospace, fixed;
+       font-size: 95%;
+}
+PRE.fragment {
+       border: 1px solid #CCCCCC;
+       background-color: #f5f5f5;
+       margin-top: 4px;
+       margin-bottom: 4px;
+       margin-left: 2px;
+       margin-right: 8px;
+       padding-left: 6px;
+       padding-right: 6px;
+       padding-top: 4px;
+       padding-bottom: 4px;
+}
+DIV.ah { 
+       background-color: black; 
+       font-weight: bold; 
+       color: #ffffff; 
+       margin-bottom: 3px; 
+       margin-top: 3px 
+}
+
+DIV.groupHeader {
+       margin-left: 16px;
+       margin-top: 12px;
+       margin-bottom: 6px;
+       font-weight: bold;
+}
+DIV.groupText { 
+       margin-left: 16px; 
+       font-style: italic; 
+       font-size: 90% 
+}
+/*BODY {
+       background: white;
+       color: black;
+       margin-right: 20px;
+       margin-left: 20px;
+}*/
+TD.indexkey {
+       background-color: #e8eef2;
+       font-weight: bold;
+       padding-right  : 10px;
+       padding-top    : 2px;
+       padding-left   : 10px;
+       padding-bottom : 2px;
+       margin-left    : 0px;
+       margin-right   : 0px;
+       margin-top     : 2px;
+       margin-bottom  : 2px;
+       border: 1px solid #CCCCCC;
+}
+TD.indexvalue {
+       background-color: #e8eef2;
+       font-style: italic;
+       padding-right  : 10px;
+       padding-top    : 2px;
+       padding-left   : 10px;
+       padding-bottom : 2px;
+       margin-left    : 0px;
+       margin-right   : 0px;
+       margin-top     : 2px;
+       margin-bottom  : 2px;
+       border: 1px solid #CCCCCC;
+}
+TR.memlist {
+       background-color: #f0f0f0; 
+}
+P.formulaDsp { 
+       text-align: center; 
+}
+IMG.formulaDsp {
+}
+IMG.formulaInl { 
+       vertical-align: middle; 
+}
+SPAN.keyword       { color: #008000 }
+SPAN.keywordtype   { color: #604020 }
+SPAN.keywordflow   { color: #e08000 }
+SPAN.comment       { color: #800000 }
+SPAN.preprocessor  { color: #806020 }
+SPAN.stringliteral { color: #002080 }
+SPAN.charliteral   { color: #008080 }
+SPAN.vhdldigit     { color: #ff00ff }
+SPAN.vhdlchar      { color: #000000 }
+SPAN.vhdlkeyword   { color: #700070 }
+SPAN.vhdllogic     { color: #ff0000 }
+
+.mdescLeft {
+       padding: 0px 8px 4px 8px;
+       font-size: 80%;
+       font-style: italic;
+       background-color: #FAFAFA;
+       border-top: 1px none #E0E0E0;
+       border-right: 1px none #E0E0E0;
+       border-bottom: 1px none #E0E0E0;
+       border-left: 1px none #E0E0E0;
+       margin: 0px;
+}
+.mdescRight {
+        padding: 0px 8px 4px 8px;
+       font-size: 80%;
+       font-style: italic;
+       background-color: #FAFAFA;
+       border-top: 1px none #E0E0E0;
+       border-right: 1px none #E0E0E0;
+       border-bottom: 1px none #E0E0E0;
+       border-left: 1px none #E0E0E0;
+       margin: 0px;
+}
+.memItemLeft {
+       padding: 1px 0px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: solid;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.memItemRight {
+       padding: 1px 8px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: solid;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.memTemplItemLeft {
+       padding: 1px 0px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: none;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.memTemplItemRight {
+       padding: 1px 8px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: none;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.memTemplParams {
+       padding: 1px 0px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: solid;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       color: #606060;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.search { 
+       color: #003399;
+       font-weight: bold;
+}
+FORM.search {
+       margin-bottom: 0px;
+       margin-top: 0px;
+}
+INPUT.search { 
+       font-size: 75%;
+       color: #000080;
+       font-weight: normal;
+       background-color: #e8eef2;
+}
+TD.tiny { 
+       font-size: 75%;
+}
+a {
+       color: #1A41A8;
+}
+a:visited {
+       color: #2A3798;
+}
+.dirtab { 
+       padding: 4px;
+       border-collapse: collapse;
+       border: 1px solid #84b0c7;
+}
+TH.dirtab { 
+       background: #e8eef2;
+       font-weight: bold;
+}
+HR { 
+       height: 1px;
+       border: none;
+       border-top: 1px solid black;
+}
+
+/* Style for detailed member documentation */
+.memtemplate {
+       font-size: 80%;
+       color: #606060;
+       font-weight: normal;
+       margin-left: 3px;
+} 
+.memnav { 
+       background-color: #eeeeee;
+       border: 1px solid #dddddd;
+       text-align: center;
+       margin: 2px;
+       margin-right: 15px;
+       padding: 2px;
+}
+.memitem {
+       padding: 4px;
+       background-color: #eeeeee;
+       border-width: 1px;
+       border-style: solid;
+       border-color: #dddddd;
+       -moz-border-radius: 4px 4px 4px 4px;
+}
+.memname {
+       white-space: nowrap;
+       font-weight: bold;
+        color: #ffffff;
+}
+.memdoc{
+       padding-left: 10px;
+}
+.memproto {
+       background-color: #111111;
+       width: 100%;
+       border-width: 1px;
+       border-style: solid;
+       border-color: #000000;
+       font-weight: bold;
+       -moz-border-radius: 4px 4px 4px 4px;
+}
+.paramkey {
+       text-align: right;
+       color: #ffffff;
+}
+.paramtype {
+       white-space: nowrap;
+       color: #aaaaaa;
+}
+.paramname {
+       color: #ff0000;
+       font-style: italic;
+       white-space: nowrap;
+}
+/* End Styling for detailed member documentation */
+
+/* for the tree view */
+.ftvtree {
+       font-family: sans-serif;
+       margin:0.5em;
+}
+/* these are for tree view when used as main index */
+.directory { 
+       font-size: 9pt; 
+       font-weight: bold; 
+}
+.directory h3 { 
+       margin: 0px; 
+       margin-top: 1em; 
+       font-size: 11pt; 
+}
+
+/* The following two styles can be used to replace the root node title */
+/* with an image of your choice.  Simply uncomment the next two styles, */
+/* specify the name of your image and be sure to set 'height' to the */
+/* proper pixel height of your image. */
+
+/* .directory h3.swap { */
+/*     height: 61px; */
+/*     background-repeat: no-repeat; */
+/*     background-image: url("yourimage.gif"); */
+/* } */
+/* .directory h3.swap span { */
+/*     display: none; */
+/* } */
+
+.directory > h3 { 
+       margin-top: 0; 
+}
+.directory p { 
+       margin: 0px; 
+       white-space: nowrap; 
+}
+.directory div { 
+       display: none; 
+       margin: 0px; 
+}
+.directory img { 
+       vertical-align: -30%; 
+}
+/* these are for tree view when not used as main index */
+.directory-alt { 
+       font-size: 100%; 
+       font-weight: bold; 
+}
+.directory-alt h3 { 
+       margin: 0px; 
+       margin-top: 1em; 
+       font-size: 11pt; 
+}
+.directory-alt > h3 { 
+       margin-top: 0; 
+}
+.directory-alt p { 
+       margin: 0px; 
+       white-space: nowrap; 
+}
+.directory-alt div { 
+       display: none; 
+       margin: 0px; 
+}
+.directory-alt img { 
+       vertical-align: -30%; 
+}
+
diff --git a/doc/img/eeze.png b/doc/img/eeze.png
new file mode 100644 (file)
index 0000000..1aeb5b1
Binary files /dev/null and b/doc/img/eeze.png differ
diff --git a/doc/img/foot_bg.png b/doc/img/foot_bg.png
new file mode 100644 (file)
index 0000000..b24f3a4
Binary files /dev/null and b/doc/img/foot_bg.png differ
diff --git a/doc/img/head_bg.png b/doc/img/head_bg.png
new file mode 100644 (file)
index 0000000..081dc13
Binary files /dev/null and b/doc/img/head_bg.png differ
diff --git a/doc/img/header_menu_background.png b/doc/img/header_menu_background.png
new file mode 100644 (file)
index 0000000..e978743
Binary files /dev/null and b/doc/img/header_menu_background.png differ
diff --git a/doc/img/header_menu_background_last.png b/doc/img/header_menu_background_last.png
new file mode 100644 (file)
index 0000000..88c116c
Binary files /dev/null and b/doc/img/header_menu_background_last.png differ
diff --git a/doc/img/header_menu_current_background.png b/doc/img/header_menu_current_background.png
new file mode 100644 (file)
index 0000000..de97c92
Binary files /dev/null and b/doc/img/header_menu_current_background.png differ
diff --git a/doc/img/header_menu_unselected_background.png b/doc/img/header_menu_unselected_background.png
new file mode 100644 (file)
index 0000000..50e5fd8
Binary files /dev/null and b/doc/img/header_menu_unselected_background.png differ
diff --git a/doc/img/logo.png b/doc/img/logo.png
new file mode 100644 (file)
index 0000000..b3884a5
Binary files /dev/null and b/doc/img/logo.png differ
diff --git a/eeze.pc.in b/eeze.pc.in
new file mode 100644 (file)
index 0000000..606b789
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: eeze
+Description: device convenience library for efl
+@pkgconfig_requires_private@: @requirement_eeze@
+Version: @VERSION@
+Libs: -L${libdir} -leeze
+Cflags: -I${includedir}/eeze-@VMAJ@
diff --git a/eeze.spec.in b/eeze.spec.in
new file mode 100644 (file)
index 0000000..f60e372
--- /dev/null
@@ -0,0 +1,78 @@
+%{!?_rel:%{expand:%%global _rel 0.enl%{?dist}}}
+%define _missing_doc_files_terminate_build 0
+
+Summary: Device Convenience Library
+Name: @PACKAGE@
+Version: @VERSION@
+Release: %{_rel}
+License: BSD
+Group: System Environment/Libraries
+Source: http://download.enlightenment.org/releases/%{name}-%{version}.tar.gz
+Packager: %{?_packager:%{_packager}}%{!?_packager:Michael Jennings <mej@eterm.org>}
+Vendor: %{?_vendorinfo:%{_vendorinfo}}%{!?_vendorinfo:The Enlightenment Project (http://www.enlightenment.org/)}
+Distribution: %{?_distribution:%{_distribution}}%{!?_distribution:%{_vendor}}
+Requires: ecore, libudev, libmount, eject
+BuildRequires: ecore-devel, libudev-devel, libmount-devel
+URL: http://www.enlightenment.org/
+BuildRoot: %{_tmppath}/%{name}-%{version}-root
+
+%description
+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:
+  * If a cdrom has a disk inserted
+  * The temperature of a cpu core
+  * The remaining power left in a battery
+  * The current power consumption of various parts
+  * 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.
+
+%package devel
+Summary: Development files for Eeze
+Group: System Environment/Libraries
+Requires: %{name} = %{version}
+Requires: ecore-devel, libudev-devel
+
+%description devel
+Headers, static libraries, test programs and documentation for Eeze
+
+%prep
+%setup -q
+
+%build
+%{configure} --prefix=%{_prefix}
+%{__make} %{?_smp_mflags} %{?mflags}
+
+%install
+%{__make} %{?mflags_install} DESTDIR=$RPM_BUILD_ROOT install
+
+%clean
+test "x$RPM_BUILD_ROOT" != "x/" && rm -rf $RPM_BUILD_ROOT
+
+%post
+/sbin/ldconfig
+
+%postun
+/sbin/ldconfig
+
+%files
+%defattr(-, root, root)
+%doc AUTHORS COPYING README
+%{_libdir}/*.so.*
+#%{_libdir}/enlightenment/utils/eeze_scanner
+%{_bindir}/*
+
+%files devel
+%defattr(-, root, root)
+%{_includedir}/*
+%{_libdir}/*.a
+%{_libdir}/*.so
+%{_libdir}/*.la
+%{_libdir}/pkgconfig/*
+
+%changelog
diff --git a/m4/ac_attribute.m4 b/m4/ac_attribute.m4
new file mode 100644 (file)
index 0000000..23479a9
--- /dev/null
@@ -0,0 +1,47 @@
+dnl Copyright (C) 2004-2008 Kim Woelders
+dnl Copyright (C) 2008 Vincent Torri <vtorri at univ-evry dot fr>
+dnl That code is public domain and can be freely used or copied.
+dnl Originally snatched from somewhere...
+
+dnl Macro for checking if the compiler supports __attribute__
+
+dnl Usage: AC_C___ATTRIBUTE__
+dnl call AC_DEFINE for HAVE___ATTRIBUTE__ and __UNUSED__
+dnl if the compiler supports __attribute__, HAVE___ATTRIBUTE__ is
+dnl defined to 1 and __UNUSED__ is defined to __attribute__((unused))
+dnl otherwise, HAVE___ATTRIBUTE__ is not defined and __UNUSED__ is
+dnl defined to nothing.
+
+AC_DEFUN([AC_C___ATTRIBUTE__],
+[
+
+AC_MSG_CHECKING([for __attribute__])
+
+AC_CACHE_VAL([ac_cv___attribute__],
+   [AC_TRY_COMPILE(
+       [
+#include <stdlib.h>
+
+int func(int x);
+int foo(int x __attribute__ ((unused)))
+{
+   exit(1);
+}
+       ],
+       [],
+       [ac_cv___attribute__="yes"],
+       [ac_cv___attribute__="no"]
+    )])
+
+AC_MSG_RESULT($ac_cv___attribute__)
+
+if test "x${ac_cv___attribute__}" = "xyes" ; then
+   AC_DEFINE([HAVE___ATTRIBUTE__], [1], [Define to 1 if your compiler has __attribute__])
+   AC_DEFINE([__UNUSED__], [__attribute__((unused))], [Macro declaring a function argument to be unused])
+  else
+    AC_DEFINE([__UNUSED__], [], [Macro declaring a function argument to be unused])
+fi
+
+])
+
+dnl End of ac_attribute.m4
diff --git a/m4/efl_binary.m4 b/m4/efl_binary.m4
new file mode 100644 (file)
index 0000000..0ad38ce
--- /dev/null
@@ -0,0 +1,78 @@
+dnl Copyright (C) 2010 Vincent Torri <vtorri at univ-evry dot fr>
+dnl That code is public domain and can be freely used or copied.
+
+dnl Macro that checks if a binary is built or not
+
+dnl Usage: EFL_ENABLE_BIN(binary, dep[, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Call AC_SUBST(BINARY_PRG) (BINARY is the uppercase of binary, - being transformed into _)
+dnl Define have_binary (- is transformed into _)
+dnl Define conditional BUILD_BINARY (BINARY is the uppercase of binary, - being transformed into _)
+
+AC_DEFUN([EFL_ENABLE_BIN],
+[
+
+m4_pushdef([UP], m4_translit([[$1]], [-a-z], [_A-Z]))dnl
+m4_pushdef([DOWN], m4_translit([[$1]], [-A-Z], [_a-z]))dnl
+
+dnl configure option
+
+AC_ARG_ENABLE([$1],
+   [AC_HELP_STRING([--disable-$1], [disable building of ]DOWN)],
+   [
+    if test "x${enableval}" = "xyes" ; then
+       have_[]m4_defn([DOWN])="yes"
+    else
+       have_[]m4_defn([DOWN])="no"
+    fi
+   ],
+   [have_[]m4_defn([DOWN])=$2])
+
+AC_MSG_CHECKING([whether to build ]DOWN[ binary])
+AC_MSG_RESULT([$have_[]m4_defn([DOWN])])
+
+if test "x$have_[]m4_defn([DOWN])" = "xyes"; then
+   UP[]_PRG=DOWN[${EXEEXT}]
+fi
+
+AC_SUBST(UP[]_PRG)
+
+AM_CONDITIONAL(BUILD_[]UP, test "x$have_[]m4_defn([DOWN])" = "xyes")
+
+AS_IF([test "x$have_[]m4_defn([DOWN])" = "xyes"], [$3], [$4])
+
+])
+
+dnl Macro that specifies the binary to be used
+
+dnl Usage: EFL_WITH_BIN(binary, package, msg)
+dnl Call AC_SUBST(BINARY_PRG) (BINARY is the uppercase of binary, - being transformed into _)
+dnl Define with_binary (- is transformed into _)
+dnl Define conditional BUILD_BINARY (BINARY is the uppercase of binary, - being transformed into _)
+
+AC_DEFUN([EFL_WITH_BIN],
+[
+
+m4_pushdef([UP], m4_translit([[$1]], [-a-z], [_A-Z]))dnl
+m4_pushdef([DOWN], m4_translit([[$1]], [-A-Z], [_a-z]))dnl
+
+AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+AC_MSG_NOTICE([$PKG_CONFIG])
+
+with_[]m4_defn([DOWN])=m4_esyscmd($PKG_CONFIG --variable=prefix $2)/bin/m4_defn([DOWN])
+
+dnl configure option
+
+AC_ARG_WITH([$1],
+   [AC_HELP_STRING([--with-$1-bin=PATH], [specify a specific path to ]DOWN)],
+   [
+    with_[]m4_defn([DOWN])=$withval
+    _efl_msg="( explicitely set)"
+   ])
+
+AC_MSG_NOTICE([$msg: ]m4_defn([DOWN])[$_efl_msg])
+
+AC_SUBST(with_[]m4_defn([DOWN]))
+
+AS_IF([test "x$have_[]m4_defn([DOWN])" = "xyes"], [$4], [$5])
+
+])
diff --git a/m4/efl_compiler_flag.m4 b/m4/efl_compiler_flag.m4
new file mode 100644 (file)
index 0000000..618c6a6
--- /dev/null
@@ -0,0 +1,57 @@
+dnl Copyright (C) 2010 Vincent Torri <vtorri at univ-evry dot fr>
+dnl                and Albin Tonnerre <albin dot tonnerre at gmail dot com>
+dnl That code is public domain and can be freely used or copied.
+
+dnl Macro that checks if a compiler flag is supported by the compiler.
+
+dnl Usage: EFL_COMPILER_FLAG(flag)
+dnl flag is added to CFLAGS if supported.
+
+AC_DEFUN([EFL_COMPILER_FLAG],
+[
+
+CFLAGS_save="${CFLAGS}"
+CFLAGS="${CFLAGS} $1"
+  
+AC_LANG_PUSH([C])
+AC_MSG_CHECKING([whether the compiler supports $1])
+
+AC_COMPILE_IFELSE(
+   [AC_LANG_PROGRAM([[]])],
+   [have_flag="yes"],
+   [have_flag="no"])
+AC_MSG_RESULT([${have_flag}])
+
+if test "x${have_flag}" = "xno" ; then
+   CFLAGS="${CFLAGS_save}"
+fi
+AC_LANG_POP([C])
+
+])
+
+dnl Macro that checks if a linker flag is supported by the compiler.
+
+dnl Usage: EFL_LINKER_FLAG(flag)
+dnl flag is added to CFLAGS if supported (will be passed to ld anyway).
+
+AC_DEFUN([EFL_LINKER_FLAG],
+[
+
+CFLAGS_save="${CFLAGS}"
+CFLAGS="${CFLAGS} $1"
+  
+AC_LANG_PUSH([C])
+AC_MSG_CHECKING([whether the compiler supports $1])
+
+AC_LINK_IFELSE(
+   [AC_LANG_PROGRAM([[]])],
+   [have_flag="yes"],
+   [have_flag="no"])
+AC_MSG_RESULT([${have_flag}])
+
+if test "x${have_flag}" = "xno" ; then
+   CFLAGS="${CFLAGS_save}"
+fi
+AC_LANG_POP([C])
+
+])
diff --git a/m4/efl_doxygen.m4 b/m4/efl_doxygen.m4
new file mode 100644 (file)
index 0000000..dd6bc3e
--- /dev/null
@@ -0,0 +1,99 @@
+dnl Copyright (C) 2008 Vincent Torri <vtorri at univ-evry dot fr>
+dnl That code is public domain and can be freely used or copied.
+
+dnl Macro that check if doxygen is available or not.
+
+dnl EFL_CHECK_DOXYGEN([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for the doxygen program
+dnl Defines efl_doxygen
+dnl Defines the automake conditionnal EFL_BUILD_DOC
+dnl
+AC_DEFUN([EFL_CHECK_DOXYGEN],
+[
+
+dnl
+dnl Disable the build of the documentation
+dnl
+AC_ARG_ENABLE([doc],
+   [AC_HELP_STRING(
+       [--disable-doc],
+       [Disable documentation build @<:@default=enabled@:>@])],
+   [
+    if test "x${enableval}" = "xyes" ; then
+       efl_enable_doc="yes"
+    else
+       efl_enable_doc="no"
+    fi
+   ],
+   [efl_enable_doc="yes"])
+
+AC_MSG_CHECKING([whether to build documentation])
+AC_MSG_RESULT([${efl_enable_doc}])
+
+if test "x${efl_enable_doc}" = "xyes" ; then
+
+dnl
+dnl Specify the file name, without path
+dnl
+
+   efl_doxygen="doxygen"
+
+   AC_ARG_WITH([doxygen],
+      [AC_HELP_STRING(
+          [--with-doxygen=FILE],
+          [doxygen program to use @<:@default=doxygen@:>@])],
+dnl
+dnl Check the given doxygen program.
+dnl
+      [efl_doxygen=${withval}
+       AC_CHECK_PROG([efl_have_doxygen],
+          [${efl_doxygen}],
+          [yes],
+          [no])
+       if test "x${efl_have_doxygen}" = "xno" ; then
+          echo "WARNING:"
+          echo "The doxygen program you specified:"
+          echo "${efl_doxygen}"
+          echo "was not found.  Please check the path and make sure "
+          echo "the program exists and is executable."
+          AC_MSG_WARN([no doxygen detected. Documentation will not be built])
+       fi
+      ],
+      [AC_CHECK_PROG([efl_have_doxygen],
+          [${efl_doxygen}],
+          [yes],
+          [no])
+       if test "x${efl_have_doxygen}" = "xno" ; then
+          echo "WARNING:"
+          echo "The doxygen program was not found in your execute path."
+          echo "You may have doxygen installed somewhere not covered by your path."
+          echo ""
+          echo "If this is the case make sure you have the packages installed, AND"
+          echo "that the doxygen program is in your execute path (see your"
+          echo "shell manual page on setting the \$PATH environment variable), OR"
+          echo "alternatively, specify the program to use with --with-doxygen."
+          AC_MSG_WARN([no doxygen detected. Documentation will not be built])
+       fi
+      ])
+fi
+
+dnl
+dnl Substitution
+dnl
+AC_SUBST([efl_doxygen])
+
+if ! test "x${efl_have_doxygen}" = "xyes" ; then
+   efl_enable_doc="no"
+fi
+
+AM_CONDITIONAL(EFL_BUILD_DOC, test "x${efl_enable_doc}" = "xyes")
+
+if test "x${efl_enable_doc}" = "xyes" ; then
+  m4_default([$1], [:])
+else
+  m4_default([$2], [:])
+fi
+
+])
+
+dnl End of doxygen.m4
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..97baf85
--- /dev/null
@@ -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 (file)
index 0000000..280006d
--- /dev/null
@@ -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 = $(bindir)
+
+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)$(bindir)/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 (file)
index 0000000..46c4006
--- /dev/null
@@ -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 (file)
index 0000000..1f1c561
--- /dev/null
@@ -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 (file)
index 0000000..2acd736
--- /dev/null
@@ -0,0 +1,453 @@
+#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);
+        dev->poller = 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);
+          break;
+        default:
+          INF("Changed volume '%s'", device);
+          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);
+          dev->poller = ecore_poller_add(ECORE_POLLER_CORE, 32,
+                                         (Ecore_Task_Cb)cdrom_timer, dev);
+          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)
+              {
+                 if (dev->poller) ecore_poller_del(dev->poller);
+                 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);
+          break;
+        default:
+          INF("Changed device '%s'", device);
+          break;
+     }
+}
+
+static void
+es_exit(int sig)
+{
+   ecore_con_server_del(svr);
+   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)
+{
+   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);
+
+   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, "eeze_scanner", 0, NULL);
+   EINA_SAFETY_ON_NULL_GOTO(svr, 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 (file)
index 0000000..a975793
--- /dev/null
@@ -0,0 +1,33 @@
+#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
+{
+   Ecore_Poller *poller;
+   const char *device;
+   Eina_Bool mounted;
+} Eeze_Scanner_Device;
+
+#endif
diff --git a/src/bin/eeze_udev_test.c b/src/bin/eeze_udev_test.c
new file mode 100644 (file)
index 0000000..130771a
--- /dev/null
@@ -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 (file)
index 0000000..75d5ebb
--- /dev/null
@@ -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 (file)
index 0000000..7c8a911
--- /dev/null
@@ -0,0 +1,560 @@
+/**
+ @brief Eeze Device Library
+ *
+ @mainpage Eeze
+ @image html  eeze.png
+ @version 1.7.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.7
+    */
+   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 7
+
+   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.7
+ */
+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 (file)
index 0000000..36079b3
--- /dev/null
@@ -0,0 +1,567 @@
+#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_DISK_MOUNTOPT_NODEV = (1 << 7) /**< @since 1.7 */
+} 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 (file)
index 0000000..97a17ca
--- /dev/null
@@ -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 (file)
index 0000000..b14e44d
--- /dev/null
@@ -0,0 +1,43 @@
+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
+if NEW_LIBMOUNT
+  libeeze_la_SOURCES += eeze_disk_libmount_new.c
+else
+  libeeze_la_SOURCES += eeze_disk_libmount.c
+endif
+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 (file)
index 0000000..8d1aeec
--- /dev/null
@@ -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 (file)
index 0000000..885f313
--- /dev/null
@@ -0,0 +1,495 @@
+#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 },
+   { "nodev", EEZE_DISK_MOUNTOPT_NODEV, 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_new.c b/src/lib/eeze_disk_libmount_new.c
new file mode 100644 (file)
index 0000000..5811518
--- /dev/null
@@ -0,0 +1,525 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef USE_UNSTABLE_LIBMOUNT_API
+# define USE_UNSTABLE_LIBMOUNT_API 1
+#endif
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <Ecore.h>
+#include <Eeze.h>
+#include <Eeze_Disk.h>
+#include <libmount.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 },
+   { "nodev", EEZE_DISK_MOUNTOPT_NODEV, 0 },
+   { NULL, 0, 0 }
+};
+typedef struct libmnt_table libmnt_table;
+typedef struct libmnt_fs libmnt_fs;
+typedef struct libmnt_cache libmnt_cache;
+static Ecore_File_Monitor *_fstab_mon = NULL;
+static Eina_Bool _watching = 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;
+extern Eina_List *_eeze_disks;
+
+static Ecore_Fd_Handler *_mountinfo_fdh = NULL;
+static int _mountinfo = -1;
+
+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 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 (_fstab_scan_active)
+     /* prevent scans from triggering a scan */
+     return;
+
+   bak = _eeze_mount_mtab;
+   _eeze_mount_mtab = _eeze_mount_tab_parse(path);
+   if (!_eeze_mount_mtab)
+     {
+        ERR("Could not parse %s! keeping old tab...", path);
+        goto error;
+     }
+
+   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;
+}
+
+/* on tab change, check differences
+ * based on code from findmnt
+ */
+static Eina_Bool
+_eeze_mount_fdh(void *d __UNUSED__, Ecore_Fd_Handler *fdh __UNUSED__)
+{
+   libmnt_table *tb_new;
+   libmnt_fs *old, *new;
+   int change;
+   struct libmnt_iter *itr = NULL;
+   struct libmnt_tabdiff *diff = NULL;
+
+   tb_new = mnt_new_table();
+   EINA_SAFETY_ON_NULL_RETURN_VAL(tb_new, ECORE_CALLBACK_RENEW);
+   EINA_SAFETY_ON_TRUE_GOTO(mnt_table_set_parser_errcb(tb_new, _eeze_mount_tab_parse_errcb), err);
+   itr = mnt_new_iter(MNT_ITER_BACKWARD);
+   EINA_SAFETY_ON_NULL_GOTO(itr, err);
+   diff = mnt_new_tabdiff();
+   EINA_SAFETY_ON_NULL_GOTO(diff, err);
+   if (mnt_table_parse_file(tb_new, "/proc/self/mountinfo"))
+     {
+        ERR("PARSING FAILED FOR /proc/self/mountinfo! THIS IS WEIRD!");
+        goto err;
+     }
+   change = mnt_diff_tables(diff, _eeze_mount_mtab, tb_new);
+   if (change < 0)
+     {
+        ERR("DIFFING FAILED FOR /proc/self/mountinfo! THIS IS ALSO WEIRD!");
+        goto err;
+     }
+   if (!change) goto err;
+   while (!mnt_tabdiff_next_change(diff, itr, &old, &new, &change))
+     {
+        const char *src;
+        Eeze_Disk *disk;
+        Eina_Bool found =  EINA_FALSE;
+        Eeze_Event_Disk_Mount *e;
+        Eina_List *l;
+
+        src = mnt_fs_get_source(new);
+        if (!src) continue;
+        EINA_LIST_FOREACH(_eeze_disks, l, disk)
+          {
+             if (!strcmp(src, eeze_disk_devpath_get(disk)))
+               {
+                  found = EINA_TRUE;
+                  break;
+               }
+          }
+        if (!found) continue;
+        switch (change)
+          {
+           case MNT_TABDIFF_MOUNT:
+             disk->mounted = EINA_TRUE;
+             eina_stringshare_replace(&disk->mount_point, mnt_fs_get_target(new));
+             if (disk->mount_status) break;
+             e = malloc(sizeof(Eeze_Event_Disk_Mount));
+             if (e)
+               {
+                  e->disk = disk;
+                  ecore_event_add(EEZE_EVENT_DISK_MOUNT, e, NULL, NULL);
+               }
+             break;
+           case MNT_TABDIFF_UMOUNT:
+             if (!mnt_fs_get_target(new))
+               disk->mounted = EINA_FALSE;
+             eina_stringshare_replace(&disk->mount_point, NULL);
+             if (disk->mount_status) break;
+             e = malloc(sizeof(Eeze_Event_Disk_Mount));
+             if (e)
+               {
+                  e->disk = disk;
+                  ecore_event_add(EEZE_EVENT_DISK_UNMOUNT, e, NULL, NULL);
+               }
+             break;
+           /* anything could have happened here, send both events to flush */
+           case MNT_TABDIFF_REMOUNT:
+           case MNT_TABDIFF_MOVE:
+             if (!mnt_fs_get_target(new))
+               disk->mounted = EINA_FALSE;
+             eina_stringshare_replace(&disk->mount_point, mnt_fs_get_target(new));
+             if (disk->mount_status) break;
+             e = malloc(sizeof(Eeze_Event_Disk_Mount));
+             if (e)
+               {
+                  e->disk = disk;
+                  ecore_event_add(EEZE_EVENT_DISK_UNMOUNT, e, NULL, NULL);
+               }
+             e = malloc(sizeof(Eeze_Event_Disk_Mount));
+             if (e)
+               {
+                  e->disk = disk;
+                  ecore_event_add(EEZE_EVENT_DISK_MOUNT, e, NULL, NULL);
+               }
+           default:
+             break;
+          }
+     }
+
+   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);
+   mnt_free_table(_eeze_mount_mtab);
+   _eeze_mount_mtab = tb_new;
+   return ECORE_CALLBACK_RENEW;
+err:
+   if (tb_new) mnt_free_table(tb_new);
+   if (itr) mnt_free_iter(itr);
+   if (diff) mnt_free_tabdiff(diff);
+   return ECORE_CALLBACK_RENEW;
+}
+
+/*
+ *
+ * INVISIBLE
+ *
+ */
+
+Eina_Bool
+eeze_libmount_init(void)
+{
+   /* placeholder */
+   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();
+}
+
+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_source(_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;
+
+   bak = _eeze_mount_tab_parse("/proc/self/mountinfo");
+   EINA_SAFETY_ON_NULL_GOTO(bak, error);
+
+   mnt_free_table(_eeze_mount_mtab);
+   _eeze_mount_mtab = bak;
+   bak = _eeze_mount_tab_parse("/etc/fstab");
+   EINA_SAFETY_ON_NULL_GOTO(bak, 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);
+
+   _mountinfo = open("/proc/self/mountinfo", O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+   if (_mountinfo < 0) goto error;
+   if (fcntl(_mountinfo, F_SETFL, O_NONBLOCK) < 0) goto error;
+   
+   _mountinfo_fdh = ecore_main_fd_handler_file_add(_mountinfo, ECORE_FD_ERROR, _eeze_mount_fdh, NULL, NULL, NULL);
+   if (!_mountinfo_fdh) goto error;
+   _fstab_mon = ecore_file_monitor_add("/etc/fstab", _eeze_mount_tab_watcher, NULL);
+   _watching = EINA_TRUE;
+
+  return EINA_TRUE;
+
+error:
+   if (_mountinfo >= 0) close(_mountinfo);
+   _mountinfo = -1;
+   if (!_eeze_mount_mtab)
+     ERR("Could not parse /proc/self/mountinfo!");
+   else
+     {
+        ERR("Could not parse /etc/fstab!");
+        mnt_free_table(_eeze_mount_mtab);
+     }
+   _eeze_mount_mtab = _eeze_mount_fstab = NULL;
+   return EINA_FALSE;
+}
+
+EAPI void
+eeze_mount_tabs_unwatch(void)
+{
+   if (!_watching)
+     return;
+
+   ecore_main_fd_handler_del(_mountinfo_fdh);
+   ecore_file_monitor_del(_fstab_mon);
+   close(_mountinfo);
+   _mountinfo = -1;
+   _fstab_mon = NULL;
+   _watching = EINA_FALSE;
+}
+
+EAPI Eina_Bool
+eeze_mount_mtab_scan(void)
+{
+   libmnt_table *bak;
+
+   if (_watching)
+     return EINA_TRUE;
+
+   bak = _eeze_mount_tab_parse("/proc/self/mountinfo");
+   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 (file)
index 0000000..20df62e
--- /dev/null
@@ -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 (file)
index 0000000..24c0ae4
--- /dev/null
@@ -0,0 +1,465 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#include <Ecore.h>
+#include <Eeze.h>
+#include <Eeze_Disk.h>
+
+#include "eeze_udev_private.h"
+#include "eeze_disk_private.h"
+
+#define EEZE_MOUNT_DEFAULT_OPTS "noexec,nosuid,utf8"
+
+EAPI int EEZE_EVENT_DISK_MOUNT = 0;
+EAPI int EEZE_EVENT_DISK_UNMOUNT = 0;
+EAPI int EEZE_EVENT_DISK_EJECT = 0;
+EAPI int EEZE_EVENT_DISK_ERROR = 0;
+static Ecore_Event_Handler *_mount_handler = NULL;
+Eina_List *eeze_events = NULL;
+
+/*
+ *
+ * PRIVATE
+ *
+ */
+
+static void
+_eeze_disk_mount_error_free(void *data __UNUSED__, Eeze_Event_Disk_Error *de)
+{
+   if (!de)
+     return;
+
+   eina_stringshare_del(de->message);
+   free(de);
+}
+
+static void
+_eeze_disk_mount_error_handler(Eeze_Disk *disk, const char *error)
+{
+   Eeze_Event_Disk_Error *de;
+
+   ERR("%s", error);
+   if (!(de = calloc(1, sizeof(Eeze_Event_Disk_Error))))
+     return;
+
+   de->disk = disk;
+   de->message = eina_stringshare_add(error);
+   /* FIXME: placeholder since currently there are only mount-type errors */
+   ecore_event_add(EEZE_EVENT_DISK_ERROR, de, (Ecore_End_Cb)_eeze_disk_mount_error_free, NULL);
+}
+
+static Eina_Bool
+_eeze_disk_mount_result_handler(void *data __UNUSED__, int type __UNUSED__, Ecore_Exe_Event_Del *ev)
+{
+   Eeze_Disk *disk;
+   Eina_List *l;
+   Eeze_Event_Disk_Mount *e;
+
+   if ((!ev) || (!ev->exe))
+     return ECORE_CALLBACK_RENEW;
+   disk = ecore_exe_data_get(ev->exe);
+
+   if ((!disk) || (!eeze_events) || (!(l = eina_list_data_find_list(eeze_events, disk))))
+     return ECORE_CALLBACK_RENEW;
+
+   eeze_events = eina_list_remove_list(eeze_events, l);
+   if (!disk->mounter) /* killed */
+     {
+        disk->mount_status = EEZE_DISK_NULL;
+        return ECORE_CALLBACK_RENEW;
+     }
+   if (disk->mount_status == EEZE_DISK_MOUNTING)
+     {
+        disk->mounter = NULL;
+        if (!ev->exit_code)
+          {
+              disk->mounted = EINA_TRUE;
+              e = malloc(sizeof(Eeze_Event_Disk_Mount));
+              EINA_SAFETY_ON_NULL_RETURN_VAL(e, ECORE_CALLBACK_RENEW);
+              e->disk = disk;
+              ecore_event_add(EEZE_EVENT_DISK_MOUNT, e, NULL, NULL);
+          }
+        else if (ev->exit_code & 2)
+           _eeze_disk_mount_error_handler(disk, "system error (out of memory, cannot fork, no more loop devices)");
+        else if (ev->exit_code & 4)
+           _eeze_disk_mount_error_handler(disk, "internal mount bug");
+        else if (ev->exit_code & 8)
+           _eeze_disk_mount_error_handler(disk, "user interrupt");
+        else if (ev->exit_code & 16)
+           _eeze_disk_mount_error_handler(disk, "problems writing or locking /etc/mtab");
+        else if (ev->exit_code & 32)
+           _eeze_disk_mount_error_handler(disk, "mount failure");
+        else if (ev->exit_code & 64)
+           _eeze_disk_mount_error_handler(disk, "some mount succeeded");
+        else
+           _eeze_disk_mount_error_handler(disk, "incorrect invocation or permissions");
+     }
+   else if (disk->mount_status == EEZE_DISK_UNMOUNTING)
+     switch (ev->exit_code)
+       {
+        case 0:
+          e = malloc(sizeof(Eeze_Event_Disk_Unmount));
+          EINA_SAFETY_ON_NULL_RETURN_VAL(e, ECORE_CALLBACK_RENEW);
+          e->disk = disk;
+          disk->mounter = NULL;
+          disk->mounted = EINA_FALSE;
+          ecore_event_add(EEZE_EVENT_DISK_UNMOUNT, e, NULL, NULL);
+          break;
+
+        default:
+          if (disk->mount_fail_count++ < 3)
+            {
+               INF("Could not unmount disk, retrying");
+               disk->mounter = ecore_exe_run(eina_strbuf_string_get(disk->unmount_cmd), disk);
+               eeze_events = eina_list_append(eeze_events, disk);
+            }
+          else
+            {
+               disk->mount_fail_count = 0;
+               _eeze_disk_mount_error_handler(disk, "Maximimum number of mount-related failures reached");
+            }
+          return ECORE_CALLBACK_RENEW;
+       }
+     else
+       switch (ev->exit_code)
+         {
+          case 0:
+            e = malloc(sizeof(Eeze_Event_Disk_Eject));
+            EINA_SAFETY_ON_NULL_RETURN_VAL(e, ECORE_CALLBACK_RENEW);
+            e->disk = disk;
+            disk->mounter = NULL;
+            if (disk->mount_status & EEZE_DISK_UNMOUNTING)
+              {
+                 disk->mount_status |= EEZE_DISK_UNMOUNTING;
+                 disk->mounted = EINA_FALSE;
+                 ecore_event_add(EEZE_EVENT_DISK_UNMOUNT, e, NULL, NULL);
+                 eeze_disk_eject(disk);
+              }
+            else
+              ecore_event_add(EEZE_EVENT_DISK_EJECT, e, NULL, NULL);
+            break;
+
+          default:
+            if (disk->mount_fail_count++ < 3)
+              {
+                 INF("Could not eject disk, retrying");
+                 if (disk->mount_status & EEZE_DISK_UNMOUNTING)
+                   disk->mounter = ecore_exe_run(eina_strbuf_string_get(disk->unmount_cmd), disk);
+                 else
+                   disk->mounter = ecore_exe_run(eina_strbuf_string_get(disk->eject_cmd), disk);
+                 eeze_events = eina_list_append(eeze_events, disk);
+              }
+           else
+             {
+                disk->mount_fail_count = 0;
+                _eeze_disk_mount_error_handler(disk, "Maximimum number of mount-related failures reached");
+             }
+            return ECORE_CALLBACK_RENEW;
+         }
+   return ECORE_CALLBACK_RENEW;
+}
+
+/*
+ *
+ * INVISIBLE
+ *
+ */
+
+Eina_Bool
+eeze_mount_init(void)
+{
+   EEZE_EVENT_DISK_MOUNT = ecore_event_type_new();
+   EEZE_EVENT_DISK_UNMOUNT = ecore_event_type_new();
+   EEZE_EVENT_DISK_EJECT = ecore_event_type_new();
+   EEZE_EVENT_DISK_ERROR = ecore_event_type_new();
+   _mount_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
+                                           (Ecore_Event_Handler_Cb)_eeze_disk_mount_result_handler, NULL);
+   return eeze_libmount_init();
+}
+
+void
+eeze_mount_shutdown(void)
+{
+   eeze_libmount_shutdown();
+   ecore_event_handler_del(_mount_handler);
+   _mount_handler = NULL;
+}
+
+/*
+ *
+ * API
+ *
+ */
+
+EAPI Eina_Bool
+eeze_disk_mounted_get(Eeze_Disk *disk)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE);
+
+   return eeze_disk_libmount_mounted_get(disk);
+}
+
+EAPI Eina_Bool
+eeze_disk_mountopts_set(Eeze_Disk *disk, unsigned long opts)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE);
+   if (opts != disk->mount_opts)
+     disk->mount_cmd_changed = EINA_TRUE;
+   disk->mount_opts = opts;
+   if (opts & EEZE_DISK_MOUNTOPT_UID)
+     disk->uid = getuid();
+   return EINA_TRUE;
+}
+
+EAPI unsigned long
+eeze_disk_mountopts_get(Eeze_Disk *disk)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(disk, 0);
+#ifndef OLD_LIBMOUNT
+   if (!disk->mount_opts)
+     disk->mount_opts = eeze_disk_libmount_opts_get(disk);
+#endif
+   return disk->mount_opts;
+}
+
+EAPI Eina_Bool
+eeze_disk_mount_wrapper_set(Eeze_Disk *disk, const char *wrapper)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE);
+   if (wrapper) EINA_SAFETY_ON_TRUE_RETURN_VAL(!*wrapper, EINA_FALSE);
+   else
+     {
+        eina_stringshare_del(disk->mount_wrapper);
+        disk->mount_wrapper = NULL;
+        return EINA_TRUE;
+     }
+   eina_stringshare_replace(&disk->mount_wrapper, wrapper);
+   return EINA_TRUE;
+}
+
+EAPI const char *
+eeze_disk_mount_wrapper_get(Eeze_Disk *disk)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL);
+   return disk->mount_wrapper;
+}
+
+EAPI Eina_Bool
+eeze_disk_mount(Eeze_Disk *disk)
+{
+   struct stat st;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE);
+
+   if ((!disk->mount_point) && eeze_disk_libmount_mounted_get(disk))
+     return EINA_FALSE;
+
+   if (!disk->mount_cmd)
+     disk->mount_cmd = eina_strbuf_new();
+
+   if (disk->mount_cmd_changed)
+     {
+        const char *dev, *str;
+        eina_strbuf_string_free(disk->mount_cmd);
+        dev = eeze_disk_uuid_get(disk);
+        if (dev) str = "UUID=";
+        else
+          {
+             dev = eeze_disk_devpath_get(disk);
+             str = NULL;
+          }
+
+        if (!disk->mount_point)
+          {
+             const char *mp;
+             /* here we attempt to guess the mount point using libmount */
+             mp = eeze_disk_libmount_mp_lookup_by_uuid(disk->cache.uuid);
+             if (!mp)
+               {
+                  const char *devpath;
+
+                  devpath = eeze_disk_devpath_get(disk);
+                  if (devpath)
+                    {
+                       mp = eeze_disk_libmount_mp_lookup_by_devpath(devpath);
+                       eina_stringshare_del(devpath);
+                    }
+               }
+             if (!eeze_disk_mount_point_set(disk, mp))
+               /* sometimes we fail */
+               return EINA_FALSE;
+          }
+
+        if ((!disk->mount_point) || (!disk->mount_point[0])) return EINA_FALSE;
+        if (disk->mount_wrapper)
+          eina_strbuf_append_printf(disk->mount_cmd, "%s ", disk->mount_wrapper);
+        if (disk->mount_opts == EEZE_DISK_MOUNTOPT_DEFAULTS)
+          eina_strbuf_append_printf(disk->mount_cmd, EEZE_MOUNT_BIN" -o "EEZE_MOUNT_DEFAULT_OPTS" %s%s %s", str ?: "", dev, disk->mount_point);
+        else if (!disk->mount_opts)
+          eina_strbuf_append_printf(disk->mount_cmd, EEZE_MOUNT_BIN" %s%s %s", str ?: "", dev, disk->mount_point);
+        else
+          {
+             eina_strbuf_append(disk->mount_cmd, EEZE_MOUNT_BIN" -o ");
+             /* trailing commas are okay */
+             if (disk->mount_opts & EEZE_DISK_MOUNTOPT_LOOP)
+               eina_strbuf_append(disk->mount_cmd, "loop,");
+             if (disk->mount_opts & EEZE_DISK_MOUNTOPT_UTF8)
+               {
+                  const char *fstype;
+                  eina_strbuf_append(disk->mount_cmd, "utf8,");
+                  fstype = eeze_disk_fstype_get(disk);
+                  if (fstype && (!strcmp(fstype, "jfs")))
+                    eina_strbuf_append(disk->mount_cmd, "iocharset=utf8,");
+               }
+             if (disk->mount_opts & EEZE_DISK_MOUNTOPT_NOEXEC)
+               eina_strbuf_append(disk->mount_cmd, "noexec,");
+             if (disk->mount_opts & EEZE_DISK_MOUNTOPT_NODEV)
+               eina_strbuf_append(disk->mount_cmd, "nodev,");
+             if (disk->mount_opts & EEZE_DISK_MOUNTOPT_NOSUID)
+               eina_strbuf_append(disk->mount_cmd, "nosuid,");
+             if (disk->mount_opts & EEZE_DISK_MOUNTOPT_REMOUNT)
+               eina_strbuf_append(disk->mount_cmd, "remount,");
+             if (disk->mount_opts & EEZE_DISK_MOUNTOPT_UID)
+               eina_strbuf_append_printf(disk->mount_cmd, "uid=%i,", (int)disk->uid);
+             eina_strbuf_append_printf(disk->mount_cmd, " %s%s %s", str ?: "", dev, disk->mount_point);
+          }
+        disk->mount_cmd_changed = EINA_FALSE;
+     }
+
+   if (stat(disk->mount_point, &st))
+     {
+        INF("Creating not-existing mount point directory '%s'", disk->mount_point);
+        if (mkdir(disk->mount_point, S_IROTH | S_IWOTH | S_IXOTH))
+          ERR("Could not create directory: %s; hopefully this is handled by your mounter!", strerror(errno));
+     }
+   else if (!S_ISDIR(st.st_mode))
+     {
+        ERR("%s is not a directory!", disk->mount_point);
+        return EINA_FALSE;
+     }
+   INF("Mounting: %s", eina_strbuf_string_get(disk->mount_cmd));
+   disk->mounter = ecore_exe_run(eina_strbuf_string_get(disk->mount_cmd), disk);
+   if (!disk->mounter)
+     return EINA_FALSE;
+   eeze_events = eina_list_append(eeze_events, disk);
+   disk->mount_status = EEZE_DISK_MOUNTING;
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+eeze_disk_unmount(Eeze_Disk *disk)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE);
+
+   if (!eeze_disk_libmount_mounted_get(disk))
+     return EINA_TRUE;
+
+   if (!disk->unmount_cmd)
+     disk->unmount_cmd = eina_strbuf_new();
+
+   if (disk->unmount_cmd_changed)
+     {
+        eina_strbuf_string_free(disk->unmount_cmd);
+        if (disk->mount_wrapper)
+          eina_strbuf_append_printf(disk->unmount_cmd, "%s ", disk->mount_wrapper);
+        eina_strbuf_append_printf(disk->unmount_cmd, EEZE_UNMOUNT_BIN" %s", eeze_disk_devpath_get(disk));
+        disk->unmount_cmd_changed = EINA_FALSE;
+     }
+
+   INF("Unmounting: %s", eina_strbuf_string_get(disk->unmount_cmd));
+   disk->mounter = ecore_exe_run(eina_strbuf_string_get(disk->unmount_cmd), disk);
+   if (!disk->mounter)
+     return EINA_FALSE;
+
+   eeze_events = eina_list_append(eeze_events, disk);
+   disk->mount_status = EEZE_DISK_UNMOUNTING;
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+eeze_disk_eject(Eeze_Disk *disk)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE);
+
+   if (!disk->eject_cmd)
+     {
+        disk->eject_cmd = eina_strbuf_new();
+        if (disk->mount_wrapper)
+          eina_strbuf_append_printf(disk->eject_cmd, "%s ", disk->mount_wrapper);
+        eina_strbuf_append_printf(disk->eject_cmd, EEZE_EJECT_BIN" %s", eeze_disk_devpath_get(disk));
+     }
+
+   INF("Ejecting: %s", eina_strbuf_string_get(disk->eject_cmd));
+   if (eeze_disk_libmount_mounted_get(disk))
+     {
+        Eina_Bool ret;
+
+        ret = eeze_disk_unmount(disk);
+        if (ret) disk->mount_status |= EEZE_DISK_EJECTING;
+        return ret;
+     }
+   disk->mounter = ecore_exe_run(eina_strbuf_string_get(disk->eject_cmd), disk);
+   if (!disk->mounter)
+     return EINA_FALSE;
+
+   eeze_events = eina_list_append(eeze_events, disk);
+   disk->mount_status = EEZE_DISK_EJECTING;
+   return EINA_TRUE;
+}
+
+EAPI void
+eeze_disk_cancel(Eeze_Disk *disk)
+{
+   EINA_SAFETY_ON_NULL_RETURN(disk);
+   if ((!disk->mount_status) || (!disk->mounter)) return;
+   disk->mount_status = EEZE_DISK_NULL;
+   ecore_exe_kill(disk->mounter);
+   disk->mounter = NULL;
+}
+
+EAPI const char *
+eeze_disk_mount_point_get(Eeze_Disk *disk)
+{
+   const char *mp;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL);
+
+   if (disk->mount_point)
+     return disk->mount_point;
+
+   mp = eeze_disk_libmount_mp_lookup_by_devpath(eeze_disk_devpath_get(disk));
+   if (mp)
+     {
+        disk->mount_point = eina_stringshare_add(mp);
+        return disk->mount_point;
+     }
+   mp = eeze_disk_libmount_mp_lookup_by_uuid(eeze_disk_uuid_get(disk));
+   if (mp)
+     {
+        disk->mount_point = eina_stringshare_add(mp);
+        return disk->mount_point;
+     }
+   mp = eeze_disk_libmount_mp_lookup_by_label(eeze_disk_label_get(disk));
+   if (mp)
+     {
+        disk->mount_point = eina_stringshare_add(mp);
+        return disk->mount_point;
+     }
+   return NULL;
+}
+
+EAPI Eina_Bool
+eeze_disk_mount_point_set(Eeze_Disk *disk, const char *mount_point)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE);
+
+   eina_stringshare_replace(&disk->mount_point, mount_point);
+   disk->mount_cmd_changed = EINA_TRUE;
+   disk->unmount_cmd_changed = EINA_TRUE;
+   return EINA_TRUE;
+}
diff --git a/src/lib/eeze_disk_private.h b/src/lib/eeze_disk_private.h
new file mode 100644 (file)
index 0000000..0174b9e
--- /dev/null
@@ -0,0 +1,93 @@
+#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;
+   unsigned int mount_fail_count;
+
+   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 (file)
index 0000000..ef7b160
--- /dev/null
@@ -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 (file)
index 0000000..b9954cf
--- /dev/null
@@ -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 (file)
index 0000000..415f794
--- /dev/null
@@ -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 (file)
index 0000000..d9b8faf
--- /dev/null
@@ -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 (file)
index 0000000..3bd06ab
--- /dev/null
@@ -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 (file)
index 0000000..7e5b5dd
--- /dev/null
@@ -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 (file)
index 0000000..59aacbd
--- /dev/null
@@ -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 (file)
index 0000000..df858e6
--- /dev/null
@@ -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 (file)
index 0000000..78e2aab
--- /dev/null
@@ -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 (file)
index 0000000..0083b81
--- /dev/null
@@ -0,0 +1,449 @@
+#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)))
+        {
+           if (event & EEZE_UDEV_EVENT_CHANGE)
+             {
+                test = udev_device_get_sysname(device);
+                if (!test) goto error;
+                if (!strncmp(test, "loop", 4)) break;
+             }
+           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 (!(event & EEZE_UDEV_EVENT_CHANGE) && ((!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;
+}