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