diff options
author | raster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33> | 2012-08-30 09:54:57 +0000 |
---|---|---|
committer | raster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33> | 2012-08-30 09:54:57 +0000 |
commit | 75cedceb190d191366c6cdec95f938f497b48aa9 (patch) | |
tree | 777edb8860438f02c0ebb7c64c11a33bdcff10f6 | |
download | eeze-75cedceb190d191366c6cdec95f938f497b48aa9.tar.gz eeze-75cedceb190d191366c6cdec95f938f497b48aa9.tar.bz2 eeze-75cedceb190d191366c6cdec95f938f497b48aa9.zip |
EFL 1.7 svn doobies
git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/branches/eeze-1.7@75862 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33
60 files changed, 9160 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 + @@ -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> @@ -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..6fde511 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,120 @@ +2011-01-29 Carsten Haitzler (The Rasterman) + + 1.0.0 release + +2011-01-29 Mike Blumenkrantz (discomfitor/zmike) + + * added disk manipulation functions + (eeze_disk_function, eeze_disk_new, eeze_disk_new_from_mount, eeze_disk_free, eeze_disk_scan, + eeze_disk_data_set, eeze_disk_data_get, eeze_disk_syspath_get, eeze_disk_devpath_get, + eeze_disk_fstype_get, eeze_disk_vendor_get, eeze_disk_model_get, eeze_disk_serial_get, + eeze_disk_uuid_get, eeze_disk_label_get, eeze_disk_type_get, eeze_disk_removable_get, + eeze_disk_mounted_get, eeze_disk_mount, eeze_disk_unmount, eeze_disk_mount_point_get, + eeze_disk_mount_point_set, eeze_mount_tabs_watch, eeze_mount_tabs_unwatch, + eeze_mount_mtab_scan, eeze_mount_fstab_scan) + +2011-02-09 Mike Blumenkrantz (discomfitor/zmike) + + * added handling of mountopts + * iso automounting in eeze_mount + (EEZE_DISK_MOUNTOPT_UTF8, EEZE_DISK_MOUNTOPT_NOEXEC, EEZE_DISK_MOUNTOPT_NOSUID, + EEZE_DISK_MOUNTOPT_REMOUNT, eeze_disk_mountopts_set, eeze_disk_mountopts_get) + +2011-03-03 Mike Blumenkrantz (discomfitor/zmike) + + * fixed bug with watches involving filtering being too aggressive for removed/offlined devices + +2011-03-12 Mike Blumenkrantz (discomfitor/zmike) + + * added EEZE_UDEV_TYPE_NET + +2011-03-12 Mike Blumenkrantz (discomfitor/zmike) + + * added eeze_udev_syspath_get_devname + +2011-05-15 Mike Blumenkrantz (discomfitor/zmike) + + * added eeze_disk_cancel, to cancel the current pending mount/umount operation on a disk + * added a uid=%i mount option using getuid (NOT geteuid) + * added wrapper for mount command exes (such as sudo) with eeze_disk_mount_wrapper_set + and eeze_disk_mount_wrapper_get + * added functions to perform udev lookups directly on disk devices without wasting + unnecessary function calls (eeze_disk_udev_get_parent, eeze_disk_udev_get_property, + eeze_disk_udev_get_sysattr, eeze_disk_udev_walk_check_sysattr, + eeze_disk_udev_walk_get_sysattr) + +2011-05-16 Mike Blumenkrantz (discomfitor/zmike) + + * fixed bug with EEZE_UDEV_TYPE_DRIVE_* detection + * fixed eeze_udev_find_unlisted_similar to be less permissive + * added EEZE_EVENT_DISK_EJECT and eeze_disk_eject, functions for ejecting a disk + +2011-06-29 Mike Blumenkrantz (discomfitor/zmike) + + * fixed bug where EEZE_UDEV_EVENT_NONE would not match all events for watches + * fixed segv when detecting removable drives + * added eeze_scanner utility daemon + * fixed bug where watches would not properly detect disk events + +2011-07-15 Cedric Bail + + * added EEZE_UDEV_TYPE_V4L + +2011-08-01 Mike Blumenkrantz (discomfitor/zmike) + + * added fix for battery/ac detection with very recent versions of udev + +2011-11-17 Mike Blumenkrantz (discomfitor/zmike) + + * added eeze_disk_can_{mount,unmount,eject} to determine at runtime whether eeze + is capable of performing disk operations + +2011-12-02 Carsten Haitzler (The Rasterman) + + 1.1.0 release + +2011-12-02 Mike Blumenkrantz (discomfitor/zmike) + + * added network device api (eeze_net_*) and Eeze_Net.h header + +2012-01-09 Mikael Sans + + * added EEZE_UDEV_TYPE_BLUETOOTH + +2012-04-26 Carsten Haitzler (The Rasterman) + + 1.2.0 release + +2012-06-11 Mike Blumenkrantz + + * eeze_scanner socket is now readable by anyone + +2012-06-12 Mike Blumenkrantz + + * Add fallback mount using device name if a disk has no uuid + +2012-06-29 Mike Blumenkrantz + + * Fix crash in eeze_net_free() + +2012-06-29 Christophe Dumez (christophe.dumez@intel.com) + + * Added joystick detection + +2012-07-10 Mike Blumenkrantz + + * Add a check in event monitoring for disks which ensures that + device changes for loopback devices are picked up + +2012-07-23 Mike Blumenkrantz + + * Add yet another libmount backend for eeze_disk to handle current + setups which do not have mtab and instead use /proc/self/mountinfo + +2012-07-30 Mike Blumenkrantz + + * Add EEZE_DISK_MOUNTOPT_NODEV option for disabling device nodes on mount + +2012-07-31 Mike Blumenkrantz + + * Prevent mount operations from retrying infinitely on failure @@ -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 @@ -0,0 +1,31 @@ +Eeze 1.7.0 + +Changes since Eeze 1.2.0: +------------------------- + +Additions: + + * Joystick support + * Support for mtab-less systems + +Changes since Eeze 1.1.0: +------------------------- + +Additions: + + * Detect bluetooth devices. + * Network device API (eeze_net_*). + +Changes since Eeze 1.0.0: +------------------------- + +Additions: + + * more disk-related detection/info functions + * disk mounting API + * eeze_scanner utility for applications to hook for drive detection + +Fixes: + + * bugs with device detection related to newer kernel versions + * device filtering to be more accurate in some cases @@ -0,0 +1,46 @@ +Eeze 1.7.0 + +****************************************************************************** + + FOR ANY ISSUES PLEASE EMAIL: + enlightenment-devel@lists.sourceforge.net + +****************************************************************************** + + +Requirements: +------------- + +Must: + libc + ecore (at least 1.0.0) + libudev + +Suggested: + libmount + +Eeze is a library for manipulating devices with an extremely simple api. +It interfaces directly with device subsystems, avoiding such middleman daemons as +udisks/upower or hal to immediately gather device information the instant it +becomes known to the OS. This can be used to determine such things as: + * If a cdrom has a disk inserted + * The temperature of a cpu core + * The remaining power left in a battery + * The current power consumption of various parts + * Monitor in realtime the status of peripheral devices + +Each of the above examples can be performed by using only a single eeze +function, as one of the primary focuses of the library is to reduce the +complexity of managing devices. + +Eeze 1.1 adds more detailed disk detection as well as filesystem mount point manipulation. +Using a combination of udev and mount, it is possible to easily write disk-based mount services +which do not rely on any external processes or libraries aside from Eeze. +------------------------------------------------------------------------------ +COMPILING AND INSTALLING: + + ./configure + make +(as root unless you are installing in your users directories): + make install + @@ -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..5569970 --- /dev/null +++ b/configure.ac @@ -0,0 +1,294 @@ +##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## +##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## +m4_define([v_maj], [1]) +m4_define([v_min], [7]) +m4_define([v_mic], [0]) +m4_define([v_rev], m4_esyscmd([(svnversion "${SVN_REPO_PATH:-.}" | grep -v '\(export\|Unversioned directory\)' || echo 0) | awk -F : '{printf("%s\n", $1);}' | tr -d ' :MSP\n'])) +m4_if(v_rev, [0], [m4_define([v_rev], m4_esyscmd([git log 2> /dev/null | (grep -m1 git-svn-id || echo 0) | sed -e 's/.*@\([0-9]*\).*/\1/' | tr -d '\n']))]) +##-- When released, remove the dnl on the below line +m4_undefine([v_rev]) +##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## +m4_ifdef([v_rev], [m4_define([v_ver], [v_maj.v_min.v_mic.v_rev])], [m4_define([v_ver], [v_maj.v_min.v_mic])]) +m4_define([lt_cur], m4_eval(v_maj + v_min)) +m4_define([lt_rev], v_mic) +m4_define([lt_age], v_min) +##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## +##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## + +AC_INIT([eeze], [v_ver], [enlightenment-devel@lists.sourceforge.net]) +AC_PREREQ([2.52]) +AC_CONFIG_SRCDIR([configure.ac]) +AC_CONFIG_MACRO_DIR([m4]) + +AC_CONFIG_HEADERS([config.h]) +AH_TOP([ +#ifndef EFL_CONFIG_H__ +#define EFL_CONFIG_H__ +]) +AH_BOTTOM([ +#endif /* EFL_CONFIG_H__ */ +]) + +AM_INIT_AUTOMAKE([1.6 dist-bzip2]) +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl +define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl +AC_PROG_LIBTOOL + +##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## +##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## +m4_ifdef([v_rev], , [m4_define([v_rev], [0])]) +m4_ifdef([v_rel], , [m4_define([v_rel], [])]) +AC_DEFINE_UNQUOTED(VMAJ, [v_maj], [Major version]) +AC_DEFINE_UNQUOTED(VMIN, [v_min], [Minor version]) +AC_DEFINE_UNQUOTED(VMIC, [v_mic], [Micro version]) +AC_DEFINE_UNQUOTED(VREV, [v_rev], [Revison]) +version_info="lt_cur:lt_rev:lt_age" +release_info="v_rel" +AC_SUBST(version_info) +AC_SUBST(release_info) +##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## +##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## +VMAJ=v_maj +AC_SUBST(VMAJ) + +### Needed information + +AC_CANONICAL_BUILD +AC_CANONICAL_HOST + +requirement_eeze="ecore >= 1.6.99 eina >= 1.6.99 libudev" + + +### Checks for programs +AC_PROG_CC +AM_PROG_CC_C_O +AC_C___ATTRIBUTE__ + +# pkg-config +PKG_PROG_PKG_CONFIG + +# Check whether pkg-config supports Requires.private +AS_IF( + [$PKG_CONFIG --atleast-pkgconfig-version 0.22], + [pkgconfig_requires_private="Requires.private"], + [pkgconfig_requires_private="Requires"] +) +AC_SUBST(pkgconfig_requires_private) + +# doxygen program for documentation building + +EFL_CHECK_DOXYGEN([build_doc="yes"], [build_doc="no"]) + + +### Checks for libraries + +PKG_CHECK_MODULES([EEZE], [${requirement_eeze}]) + +udev_version=$(pkg-config libudev --modversion) + +if test $udev_version -lt 143;then + AC_MSG_ERROR([udev version is too old!]) +elif test $udev_version -lt 148;then + AC_MSG_WARN([Old udev version detected, enabling compat code]) + AC_DEFINE([OLD_UDEV_RRRRRRRRRRRRRR],[1],[compat functionality for udev < 148]) +fi + +eeze_mount= +PKG_CHECK_EXISTS([mount >= 2.18.0], + [ + AC_DEFINE([HAVE_EEZE_MOUNT], [1], [Eeze is mount-capable]) + AM_CONDITIONAL([HAVE_EEZE_MOUNT], [true]) + eeze_mount="yes" + ], + AM_CONDITIONAL([HAVE_EEZE_MOUNT], [false]) +) + +if test "x$eeze_mount" = "xyes";then + AC_ARG_WITH([mount], [AS_HELP_STRING([--with-mount], [specify mount bin @<:@default=detect@:>@])], [with_mount=$withval], [with_mount="detect"]) + AC_ARG_WITH([umount], [AS_HELP_STRING([--with-umount], [specify umount bin @<:@default=detect@:>@])], [with_umount=$withval], [with_umount="detect"]) + AC_ARG_WITH([eject], [AS_HELP_STRING([--with-eject], [specify eject bin @<:@default=detect@:>@])], [with_eject=$withval], [with_eject="detect"]) + PKG_CHECK_MODULES([LIBMOUNT], [mount >= 2.18.0]) + mount_v=$(pkg-config --modversion mount) + PKG_CHECK_MODULES([ECORE_FILE], [ecore-file >= 1.6.99]) + PKG_CHECK_MODULES([EET], [eet >= 1.6.99]) + PKG_CHECK_MODULES([ECORE_CON], [ecore-con >= 1.6.99]) + + if test "x$with_mount" = "xdetect";then + AC_PATH_PROG([with_mount], [mount], []) + fi + if test -z "$with_mount" ; then + AC_DEFINE_UNQUOTED([MOUNTABLE], [0], [whether mount is available]) + else + AC_DEFINE_UNQUOTED([MOUNTABLE], [1], [whether mount is available]) + fi + AC_DEFINE_UNQUOTED([EEZE_MOUNT_BIN], ["$with_mount"], [mount bin to use]) + + if test "x$with_umount" = "xdetect";then + AC_PATH_PROG([with_umount], [umount], []) + fi + if test -z "$with_umount" ; then + AC_DEFINE_UNQUOTED([UNMOUNTABLE], [0], [whether umount is available]) + else + AC_DEFINE_UNQUOTED([UNMOUNTABLE], [1], [whether umount is available]) + fi + AC_DEFINE_UNQUOTED([EEZE_UNMOUNT_BIN], ["$with_umount"], [umount bin to use]) + + if test "x$with_eject" = "xdetect";then + AC_PATH_PROG([with_eject], [eject], []) + fi + if test -z "$with_eject" ; then + AC_DEFINE_UNQUOTED([EJECTABLE], [0], [whether eject is available]) + else + AC_DEFINE_UNQUOTED([EJECTABLE], [1], [whether eject is available]) + fi + AC_DEFINE_UNQUOTED([EEZE_EJECT_BIN], ["$with_eject"], [eject bin to use]) +fi + +want_mtab= +AC_ARG_ENABLE([mtab], + [AC_HELP_STRING([--enable-mtab], + [force use of mtab for mount info @<:@default=detect@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + want_mtab="yes" + else + want_mtab="no" + fi], + [want_mtab="auto"]) + + +if test "x${want_mtab}" = "xyes" ; then + AM_CONDITIONAL([OLD_LIBMOUNT], [false]) + AM_CONDITIONAL([NEW_LIBMOUNT], [false]) +else + if test -n "$mount_v";then + AM_CONDITIONAL([OLD_LIBMOUNT], [test "$(echo $mount_v | cut -d'.' -f2)" -lt 19]) + AM_CONDITIONAL([NEW_LIBMOUNT], [test "$(echo $mount_v | cut -d'.' -f2)" -gt 19]) + else + AM_CONDITIONAL([OLD_LIBMOUNT], [false]) + AM_CONDITIONAL([NEW_LIBMOUNT], [false]) + fi +fi +AM_COND_IF([OLD_LIBMOUNT], [ + AC_DEFINE_UNQUOTED([OLD_LIBMOUNT], [1], [using first version of libmount]) + ],[]) + +AC_CHECK_HEADERS([netinet/in.h]) +want_ipv6="yes" +have_ipv6="no" + +AC_ARG_ENABLE([ipv6], + [AC_HELP_STRING([--disable-ipv6], + [disable ipv6 functionality @<:@default=detect@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + want_ipv6="yes" + else + want_ipv6="no" + fi], + [want_ipv6="auto"]) + +# Verify IPV6 availability in headers +if test "x${want_ipv6}" != "xno" ; then + AC_CHECK_TYPES([struct ipv6_mreq], + [have_ipv6="yes"], + [have_ipv6="no"], + [[ +#ifdef HAVE_NETINET_IN_H +# include <netinet/in.h> +#endif + ]]) +fi + +if test "x${have_ipv6}" = "xyes" ; then + AC_DEFINE(HAVE_IPV6, 1, [Define if IPV6 is supported]) +fi + +### Checks for header files + + +### Checks for types + + +### Checks for structures + + +### Checks for compiler characteristics + +AC_HEADER_STDC + +if ! test "x${VMIC}" = "x" ; then + EFL_COMPILER_FLAG([-Wall]) + EFL_COMPILER_FLAG([-W]) +fi + +EFL_COMPILER_FLAG([-Wshadow]) + + +### Binary + +EFL_ENABLE_BIN([eeze-udev-test], ["yes"]) +EFL_ENABLE_BIN([eeze-mount], ["yes"]) +EFL_ENABLE_BIN([eeze-disk-ls], ["yes"]) +EFL_ENABLE_BIN([eeze-umount], ["yes"]) +EFL_ENABLE_BIN([eeze-scanner], ["yes"]) + +AC_SUBST(requirement_eeze) + + +AC_OUTPUT([ +Makefile +doc/eeze.dox +doc/Makefile +doc/Doxyfile +src/Makefile +src/lib/Makefile +src/bin/Makefile +eeze.pc +eeze.spec +]) + + +##################################################################### +## Info + +echo +echo +echo +echo "------------------------------------------------------------------------" +echo "$PACKAGE $VERSION" +echo "------------------------------------------------------------------------" +echo +echo "Configuration Options Summary:" +if test "x$eeze_mount" = "xyes";then + echo + echo "Mount..................: ${with_mount}" + echo "Umount.................: ${with_umount}" + echo "Eject..................: ${with_eject}" + echo +fi +echo "Tests..................: ${have_eeze_udev_test}" +echo +echo "Demos..................:" +echo " eeze_mount...........: ${have_eeze_mount}" +echo " eeze_umount..........: ${have_eeze_umount}" +echo " eeze_disk_ls.........: ${have_eeze_disk_ls}" +echo +echo "Utilities..............:" +echo " eeze_scanner.........: ${have_eeze_scanner}" +echo +echo "IPv6...................: ${have_ipv6}" +echo +echo "Documentation..........: ${build_doc}" +echo +echo "Compilation............: make (or gmake)" +echo " CPPFLAGS.............: $CPPFLAGS" +echo " CFLAGS...............: $CFLAGS" +echo " LDFLAGS..............: $LDFLAGS" +echo +echo "Installation...........: make install (as root if needed, with 'su' or 'sudo')" +echo " prefix...............: $prefix" +echo + diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in new file mode 100644 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 ©$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 Binary files differnew file mode 100644 index 0000000..1aeb5b1 --- /dev/null +++ b/doc/img/eeze.png diff --git a/doc/img/foot_bg.png b/doc/img/foot_bg.png Binary files differnew file mode 100644 index 0000000..b24f3a4 --- /dev/null +++ b/doc/img/foot_bg.png diff --git a/doc/img/head_bg.png b/doc/img/head_bg.png Binary files differnew file mode 100644 index 0000000..081dc13 --- /dev/null +++ b/doc/img/head_bg.png diff --git a/doc/img/header_menu_background.png b/doc/img/header_menu_background.png Binary files differnew file mode 100644 index 0000000..e978743 --- /dev/null +++ b/doc/img/header_menu_background.png diff --git a/doc/img/header_menu_background_last.png b/doc/img/header_menu_background_last.png Binary files differnew file mode 100644 index 0000000..88c116c --- /dev/null +++ b/doc/img/header_menu_background_last.png diff --git a/doc/img/header_menu_current_background.png b/doc/img/header_menu_current_background.png Binary files differnew file mode 100644 index 0000000..de97c92 --- /dev/null +++ b/doc/img/header_menu_current_background.png diff --git a/doc/img/header_menu_unselected_background.png b/doc/img/header_menu_unselected_background.png Binary files differnew file mode 100644 index 0000000..50e5fd8 --- /dev/null +++ b/doc/img/header_menu_unselected_background.png diff --git a/doc/img/logo.png b/doc/img/logo.png Binary files differnew file mode 100644 index 0000000..b3884a5 --- /dev/null +++ b/doc/img/logo.png 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..f60e372 --- /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..280006d --- /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 = $(bindir) + +eeze_udev_test_SOURCES = eeze_udev_test.c +eeze_udev_test_CPPFLAGS = -I$(top_srcdir)/src/lib @EEZE_CFLAGS@ +eeze_udev_test_LDADD = $(top_builddir)/src/lib/libeeze.la @EEZE_LIBS@ + +if HAVE_EEZE_MOUNT + eeze_mount_SOURCES = eeze_mount.c + eeze_mount_CFLAGS = -I$(top_srcdir)/src/lib $(EEZE_CFLAGS) @LIBMOUNT_CFLAGS@ @ECORE_FILE_CFLAGS@ + eeze_mount_LDADD = $(top_builddir)/src/lib/libeeze.la @LIBMOUNT_LIBS@ @ECORE_FILE_LIBS@ @EEZE_LIBS@ + + eeze_umount_SOURCES = eeze_umount.c + eeze_umount_CFLAGS = -I$(top_srcdir)/src/lib $(EEZE_CFLAGS) @LIBMOUNT_CFLAGS@ @ECORE_FILE_CFLAGS@ + eeze_umount_LDADD = $(top_builddir)/src/lib/libeeze.la @LIBMOUNT_LIBS@ @ECORE_FILE_LIBS@ @EEZE_LIBS@ + + eeze_disk_ls_SOURCES = eeze_disk_ls.c + eeze_disk_ls_CFLAGS = -I$(top_srcdir)/src/lib $(EEZE_CFLAGS) @LIBMOUNT_CFLAGS@ @ECORE_FILE_CFLAGS@ + eeze_disk_ls_LDADD = $(top_builddir)/src/lib/libeeze.la @LIBMOUNT_LIBS@ @ECORE_FILE_LIBS@ @EEZE_LIBS@ + + eeze_scanner_SOURCES = eeze_scanner.c + eeze_scanner_CFLAGS = -I$(top_srcdir)/src/lib $(EEZE_CFLAGS) @LIBMOUNT_CFLAGS@ @ECORE_FILE_CFLAGS@ @ECORE_CON_CFLAGS@ @EET_CFLAGS@ + eeze_scanner_LDADD = $(top_builddir)/src/lib/libeeze.la @LIBMOUNT_LIBS@ @ECORE_FILE_LIBS@ @ECORE_CON_LIBS@ @EET_LIBS@ @EEZE_LIBS@ + includesdir = $(includedir)/eeze-@VMAJ@ + includes_HEADERS = eeze_scanner.h + +setuid_root_mode = a=rx,u+xs +install-data-hook: + @chmod $(setuid_root_mode) $(DESTDIR)$(bindir)/eeze_scanner$(EXEEXT) || true + +endif diff --git a/src/bin/eeze_disk_ls.c b/src/bin/eeze_disk_ls.c new file mode 100644 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..2acd736 --- /dev/null +++ b/src/bin/eeze_scanner.c @@ -0,0 +1,453 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <Eet.h> +#include <Eeze.h> +#include <Ecore_Con.h> +#include <Eeze_Disk.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> + +#include "eeze_scanner.h" + +#define DBG(...) EINA_LOG_DOM_DBG(es_log_dom, __VA_ARGS__) +#define INF(...) EINA_LOG_DOM_INFO(es_log_dom, __VA_ARGS__) +#define WRN(...) EINA_LOG_DOM_WARN(es_log_dom, __VA_ARGS__) +#define ERR(...) EINA_LOG_DOM_ERR(es_log_dom, __VA_ARGS__) +#define CRI(...) EINA_LOG_DOM_CRIT(es_log_dom, __VA_ARGS__) + +static int es_log_dom = -1; +static Ecore_Con_Server *svr = NULL; +static Eet_Data_Descriptor *es_edd = NULL; +static Eina_Hash *clients = NULL; + +static Eina_List *storage_devices = NULL; +static Eina_List *storage_cdrom = NULL; + +static Eina_List *volume_cdrom = NULL; +static Eina_List *volume_devices = NULL; + +static void +event_send(const char *device, Eeze_Scanner_Event_Type type, Eina_Bool volume) +{ + Eeze_Scanner_Event ev; + const Eina_List *l; + Ecore_Con_Client *cl; + + ev.device = device; + ev.type = type; + ev.volume = volume; + EINA_LIST_FOREACH(ecore_con_server_clients_get(svr), l, cl) + { + Eet_Connection *ec; + + ec = eina_hash_find(clients, cl); + if (!ec) continue; + INF("Serializing event..."); + eet_connection_send(ec, es_edd, &ev, NULL); + } +} + +static Eina_Bool +event_write(const void *data, size_t size, Ecore_Con_Client *cl) +{ + INF("Event sent!"); + ecore_con_client_send(cl, data, size); + return EINA_TRUE; +} + +static Eina_Bool +disk_mount(void *data __UNUSED__, int type __UNUSED__, Eeze_Disk *disk) +{ + Eina_List *l; + Eeze_Scanner_Device *d; + if (eeze_disk_type_get(disk) != EEZE_DISK_TYPE_CDROM) return ECORE_CALLBACK_RENEW; + + EINA_LIST_FOREACH(storage_cdrom, l, d) + { + if (d->device == eeze_disk_syspath_get(disk)) + { + d->mounted = !d->mounted; + break; + } + } + return ECORE_CALLBACK_RENEW; +} + +static void +cl_setup(Ecore_Con_Client *cl __UNUSED__, Eet_Connection *ec) +{ + Eina_List *l; + Eeze_Scanner_Device *dev; + Eeze_Scanner_Event ev; + const char *sys; + + INF("Sending initial events to new client"); + EINA_LIST_FOREACH(storage_devices, l, sys) + { + ev.device = sys; + ev.type = EEZE_SCANNER_EVENT_TYPE_ADD; + ev.volume = EINA_FALSE; + eet_connection_send(ec, es_edd, &ev, NULL); + } + EINA_LIST_FOREACH(storage_cdrom, l, dev) + { + ev.device = dev->device; + ev.type = EEZE_SCANNER_EVENT_TYPE_ADD; + ev.volume = EINA_FALSE; + eet_connection_send(ec, es_edd, &ev, NULL); + } + EINA_LIST_FOREACH(volume_devices, l, sys) + { + ev.device = sys; + ev.type = EEZE_SCANNER_EVENT_TYPE_ADD; + ev.volume = EINA_TRUE; + eet_connection_send(ec, es_edd, &ev, NULL); + } + EINA_LIST_FOREACH(volume_cdrom, l, dev) + { + ev.device = dev->device; + ev.type = EEZE_SCANNER_EVENT_TYPE_ADD; + ev.volume = EINA_TRUE; + eet_connection_send(ec, es_edd, &ev, NULL); + } +} + +static Eina_Bool +es_read(const void *eet_data __UNUSED__, size_t size __UNUSED__, void *user_data __UNUSED__) +{ + return EINA_TRUE; +} + +static Eina_Bool +cl_add(void *data __UNUSED__, int type __UNUSED__, Ecore_Con_Event_Client_Add *ev) +{ + Eet_Connection *ec; + INF("Added client"); + + ec = eet_connection_new(es_read, (Eet_Write_Cb*)event_write, ev->client); + if (!ec) + { + ERR("Could not create eet serializer! Lost client!"); + ecore_con_client_del(ev->client); + return ECORE_CALLBACK_RENEW; + } + + eina_hash_direct_add(clients, ev->client, ec); + cl_setup(ev->client, ec); + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +cl_del(void *data __UNUSED__, int type __UNUSED__, Ecore_Con_Event_Client_Del *ev) +{ + Eet_Connection *ec; + Eina_Bool d; + INF("Removed client"); + ec = eina_hash_find(clients, ev->client); + if (ec) + { + eet_connection_close(ec, &d); + eina_hash_del_by_data(clients, ec); + } + + return ECORE_CALLBACK_RENEW; +} + +static void +eet_setup(void) +{ + Eet_Data_Descriptor_Class eddc; + + if (!eet_eina_stream_data_descriptor_class_set(&eddc, sizeof(eddc), "eeze_scanner_event", sizeof(Eeze_Scanner_Event))) + { + CRI("Could not create eet data descriptor!"); + exit(1); + } + + es_edd = eet_data_descriptor_stream_new(&eddc); +#define DAT(MEMBER, TYPE) EET_DATA_DESCRIPTOR_ADD_BASIC(es_edd, Eeze_Scanner_Event, #MEMBER, MEMBER, EET_T_##TYPE) + DAT(device, INLINED_STRING); + DAT(type, UINT); + DAT(volume, UCHAR); +#undef DAT +} + +static Eina_Bool +cdrom_timer(Eeze_Scanner_Device *dev) +{ + const char *devpath; + int fd; + + /* cdrom already mounted, no need to poll */ + if (dev->mounted) return EINA_TRUE; + devpath = eeze_udev_syspath_get_devpath(dev->device); + fd = open(devpath, O_RDONLY); + if (fd < 0) + { + Eina_List *l; + + l = eina_list_data_find_list(volume_cdrom, dev); + if (l) + { + /* disc removed, delete volume */ + INF("Removed cdrom '%s'", dev->device); + volume_cdrom = eina_list_remove_list(volume_cdrom, l); + event_send(dev->device, EEZE_SCANNER_EVENT_TYPE_CHANGE, EINA_TRUE); + } + /* just in case */ + dev->mounted = EINA_FALSE; + } + else + { + if (!eina_list_data_find(volume_cdrom, dev)) + { + INF("Added cdrom '%s'", dev->device); + volume_cdrom = eina_list_append(volume_cdrom, dev); + event_send(dev->device, EEZE_SCANNER_EVENT_TYPE_CHANGE, EINA_TRUE); + } + close(fd); + } + eina_stringshare_del(devpath); + return EINA_TRUE; +} + +static void +storage_setup(void) +{ + Eina_List *l, *ll; + const char *sys; + + storage_devices = eeze_udev_find_by_type(EEZE_UDEV_TYPE_DRIVE_INTERNAL, NULL); + if (!storage_devices) + { + ERR("No storage devices found! This is not supposed to happen!"); + exit(1); + } + EINA_LIST_FOREACH(storage_devices, l, sys) + event_send(sys, EEZE_SCANNER_EVENT_TYPE_ADD, EINA_FALSE); + + ll = eeze_udev_find_by_type(EEZE_UDEV_TYPE_DRIVE_REMOVABLE, NULL); + EINA_LIST_FREE(ll, sys) + { + event_send(sys, EEZE_SCANNER_EVENT_TYPE_ADD, EINA_FALSE); + storage_devices = eina_list_append(storage_devices, sys); + } + + l = eeze_udev_find_by_type(EEZE_UDEV_TYPE_DRIVE_CDROM, NULL); + EINA_LIST_FREE(l, sys) + { + Eeze_Scanner_Device *dev; + Eeze_Disk *disk; + + dev = calloc(1, sizeof(Eeze_Scanner_Device)); + if (!dev) + { + ERR("Lost cdrom device '%s'!", sys); + eina_stringshare_del(sys); + continue; + } + disk = eeze_disk_new(sys); + if (!disk) + { + ERR("Lost cdrom device '%s'!", sys); + eina_stringshare_del(sys); + free(dev); + continue; + } + dev->device = sys; + dev->mounted = eeze_disk_mounted_get(disk); + eeze_disk_free(disk); + event_send(sys, EEZE_SCANNER_EVENT_TYPE_ADD, EINA_FALSE); + dev->poller = ecore_poller_add(ECORE_POLLER_CORE, 32, (Ecore_Task_Cb)cdrom_timer, dev); + storage_cdrom = eina_list_append(storage_cdrom, dev); + } + volume_devices = eeze_udev_find_by_type(EEZE_UDEV_TYPE_DRIVE_MOUNTABLE, NULL); + EINA_LIST_FOREACH_SAFE(volume_devices, l, ll, sys) + { + Eina_List *c; + Eeze_Scanner_Device *dev; + + EINA_LIST_FOREACH(storage_cdrom, c, dev) + if (sys == dev->device) + { + eina_stringshare_del(sys); + volume_devices = eina_list_remove_list(volume_devices, l); + volume_cdrom = eina_list_append(volume_cdrom, dev); + event_send(sys, EEZE_SCANNER_EVENT_TYPE_ADD, EINA_TRUE); + l = NULL; + break; + } + if (!l) continue; + event_send(sys, EEZE_SCANNER_EVENT_TYPE_ADD, EINA_TRUE); + } +} + +static void +cb_vol_chg(const char *device, Eeze_Udev_Event ev, void *data __UNUSED__, Eeze_Udev_Watch *watch __UNUSED__) +{ + Eina_List *l; + Eeze_Scanner_Device *dev; + + DBG("device='%s'", device); + + if (ev == EEZE_UDEV_EVENT_ONLINE) ev = EEZE_SCANNER_EVENT_TYPE_ADD; + else if (ev == EEZE_UDEV_EVENT_OFFLINE) ev = EEZE_SCANNER_EVENT_TYPE_REMOVE; + + event_send(device, ev, EINA_TRUE); + switch (ev) + { + case EEZE_UDEV_EVENT_ADD: + case EEZE_UDEV_EVENT_ONLINE: + INF("Added volume '%s'", device); + EINA_LIST_FOREACH(storage_cdrom, l, dev) + if (device == dev->device) + { + volume_cdrom = eina_list_append(volume_cdrom, dev); + return; + } + volume_devices = eina_list_append(volume_devices, eina_stringshare_add(device)); + break; + case EEZE_UDEV_EVENT_REMOVE: + case EEZE_UDEV_EVENT_OFFLINE: + INF("Removed volume '%s'", device); + EINA_LIST_FOREACH(volume_cdrom, l, dev) + if (device == dev->device) + { + volume_cdrom = eina_list_remove_list(volume_cdrom, l); + return; + } + volume_devices = eina_list_remove(volume_devices, device); + eina_stringshare_del(device); + break; + default: + INF("Changed volume '%s'", device); + break; + } +} + +static void +cb_stor_chg(const char *device, Eeze_Udev_Event ev, void *data __UNUSED__, Eeze_Udev_Watch *watch __UNUSED__) +{ + Eina_List *l; + Eeze_Scanner_Device *dev = NULL; + const char *str; + + + DBG("device='%s'", device); + switch (ev) + { + case EEZE_UDEV_EVENT_ADD: + case EEZE_UDEV_EVENT_ONLINE: + INF("Added device '%s'", device); + event_send(device, ev, EINA_FALSE); + str = eeze_udev_syspath_get_property(device, "ID_CDROM"); + if (!str) + { + storage_devices = eina_list_append(storage_devices, eina_stringshare_add(device)); + return; + } + eina_stringshare_del(str); + dev = calloc(1, sizeof(Eeze_Scanner_Device)); + dev->device = eina_stringshare_add(device); + dev->poller = ecore_poller_add(ECORE_POLLER_CORE, 32, + (Ecore_Task_Cb)cdrom_timer, dev); + storage_cdrom = eina_list_append(storage_cdrom, dev); + break; + case EEZE_UDEV_EVENT_REMOVE: + case EEZE_UDEV_EVENT_OFFLINE: + if (!eina_list_data_find(storage_devices, device)) + { + EINA_LIST_FOREACH(storage_cdrom, l, dev) + if (dev->device == device) break; + if ((!dev) || (dev->device != device)) return; + } + INF("Removed device '%s'", device); + event_send(device, ev, EINA_FALSE); + EINA_LIST_FOREACH(storage_cdrom, l, dev) + if (device == dev->device) + { + if (dev->poller) ecore_poller_del(dev->poller); + storage_cdrom = eina_list_remove_list(storage_cdrom, l); + eina_stringshare_del(dev->device); + free(dev); + return; + } + storage_devices = eina_list_remove(storage_devices, device); + eina_stringshare_del(device); + break; + default: + INF("Changed device '%s'", device); + break; + } +} + +static void +es_exit(int sig) +{ + ecore_con_server_del(svr); + exit(sig); +} + +static void +sigs_setup(void) +{ + sigset_t sigs = {{0}}; + struct sigaction s; + + sigfillset(&sigs); + sigdelset(&sigs, SIGSEGV); + sigdelset(&sigs, SIGTERM); + sigdelset(&sigs, SIGINT); + sigdelset(&sigs, SIGQUIT); + + s.sa_handler = es_exit; + s.sa_flags = 0; + sigaction(SIGTERM, &s, NULL); + sigaction(SIGSEGV, &s, NULL); + sigaction(SIGINT, &s, NULL); +} + +int +main(void) +{ + eina_init(); + ecore_init(); + ecore_con_init(); + eeze_init(); + eeze_disk_function(); + eeze_mount_tabs_watch(); + + sigs_setup(); + es_log_dom = eina_log_domain_register("eeze_scanner", EINA_COLOR_CYAN); + + eet_setup(); + clients = eina_hash_pointer_new(NULL); + EINA_SAFETY_ON_NULL_GOTO(clients, error); + + ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_ADD, (Ecore_Event_Handler_Cb)cl_add, NULL); + ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DEL, (Ecore_Event_Handler_Cb)cl_del, NULL); + ecore_event_handler_add(EEZE_EVENT_DISK_UNMOUNT, (Ecore_Event_Handler_Cb)disk_mount, NULL); + ecore_event_handler_add(EEZE_EVENT_DISK_MOUNT, (Ecore_Event_Handler_Cb)disk_mount, NULL); + + eeze_udev_watch_add(EEZE_UDEV_TYPE_DRIVE_INTERNAL, EEZE_UDEV_EVENT_NONE, cb_stor_chg, NULL); + eeze_udev_watch_add(EEZE_UDEV_TYPE_DRIVE_REMOVABLE, EEZE_UDEV_EVENT_NONE, cb_stor_chg, NULL); + eeze_udev_watch_add(EEZE_UDEV_TYPE_DRIVE_CDROM, EEZE_UDEV_EVENT_NONE, cb_stor_chg, NULL); + eeze_udev_watch_add(EEZE_UDEV_TYPE_DRIVE_MOUNTABLE, EEZE_UDEV_EVENT_NONE, cb_vol_chg, NULL); + + svr = ecore_con_server_add(ECORE_CON_LOCAL_SYSTEM, "eeze_scanner", 0, NULL); + EINA_SAFETY_ON_NULL_GOTO(svr, error); + + storage_setup(); + ecore_main_loop_begin(); + + ecore_con_server_del(svr); + return 0; +error: + ERR("Could not start up!"); + exit(1); +} diff --git a/src/bin/eeze_scanner.h b/src/bin/eeze_scanner.h new file mode 100644 index 0000000..a975793 --- /dev/null +++ b/src/bin/eeze_scanner.h @@ -0,0 +1,33 @@ +#ifndef EEZE_SCANNER_H +#define EEZE_SCANNER_H + +#include <Eeze.h> + +#define EEZE_SCANNER_EDD_SETUP(edd) \ + EET_DATA_DESCRIPTOR_ADD_BASIC((edd), Eeze_Scanner_Event, "device", device, EET_T_INLINED_STRING); \ + EET_DATA_DESCRIPTOR_ADD_BASIC((edd), Eeze_Scanner_Event, "type", type, EET_T_UINT); \ + EET_DATA_DESCRIPTOR_ADD_BASIC((edd), Eeze_Scanner_Event, "volume", volume, EET_T_UCHAR) + +typedef enum +{ + EEZE_SCANNER_EVENT_TYPE_NONE, + EEZE_SCANNER_EVENT_TYPE_ADD = EEZE_UDEV_EVENT_ADD, + EEZE_SCANNER_EVENT_TYPE_REMOVE = EEZE_UDEV_EVENT_REMOVE, + EEZE_SCANNER_EVENT_TYPE_CHANGE = EEZE_UDEV_EVENT_CHANGE +} Eeze_Scanner_Event_Type; + +typedef struct +{ + const char *device; + Eeze_Scanner_Event_Type type; + Eina_Bool volume; +} Eeze_Scanner_Event; + +typedef struct +{ + Ecore_Poller *poller; + const char *device; + Eina_Bool mounted; +} Eeze_Scanner_Device; + +#endif diff --git a/src/bin/eeze_udev_test.c b/src/bin/eeze_udev_test.c new file mode 100644 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..7c8a911 --- /dev/null +++ b/src/lib/Eeze.h @@ -0,0 +1,560 @@ +/** + @brief Eeze Device Library + * + @mainpage Eeze + @image html eeze.png + @version 1.7.0 + @author Mike Blumenkrantz (zmike/discomfitor) <michael.blumenkrantz@@gmail.com> + @date 2010-2012 + + @section intro What is Eeze? + + Eeze is a library for manipulating devices through udev with a simple and fast + api. It interfaces directly with libudev, avoiding such middleman daemons as + udisks/upower or hal, to immediately gather device information the instant it + becomes known to the system. This can be used to determine such things as: + @li If a cdrom has a disk inserted + @li The temperature of a cpu core + @li The remaining power left in a battery + @li The current power consumption of various parts + @li Monitor in realtime the status of peripheral devices + + Each of the above examples can be performed by using only a single eeze + function, as one of the primary focuses of the library is to reduce the + complexity of managing devices. + + @li @link Eeze.h Eeze functions @endlink + @li @ref udev UDEV functions + @li @ref watch Functions that watch for events + @li @ref syspath Functions that accept a device /sys/ path + @li @ref find Functions which find types of devices + @li @ref disk Disk functions + @li @ref net Net functions + @verbatim + Pants + @endverbatim + */ +#ifndef EEZE_UDEV_H +#define EEZE_UDEV_H + +#include <Eina.h> + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +#else +# define EAPI +#endif + +/** + * @file Eeze.h + * @brief Easy device manipulation. + * + * Eeze is a library for manipulating devices through udev with a simple and fast + * api. It interfaces directly with libudev, avoiding such middleman daemons as + * udisks/upower or hal, to immediately gather device information the instant it + * becomes known to the system. This can be used to determine such things as: + * @li If a cdrom has a disk inserted + * @li The temperature of a cpu core + * @li The remaining power left in a battery + * @li The current power consumption of various parts + * @li Monitor in realtime the status of peripheral devices + * Each of the above examples can be performed by using only a single eeze + * function, as one of the primary focuses of the library is to reduce the + * complexity of managing devices. + * + * + * For udev functions, see @ref udev. + */ + +/** + * @defgroup main main + * + * These are general eeze functions which include init and shutdown. + */ + +/** + * @defgroup udev udev + * + * These are functions which interact directly with udev. + */ + +/** + * @addtogroup udev + * + * These are the device subsystems of udev: + * @li ac97 + * @li acpi + * @li bdi + * @li block + * @li bsg + * @li dmi + * @li graphics + * @li hid + * @li hwmon + * @li i2c + * @li input + * @li mem + * @li misc + * @li net + * @li pci + * @li pci_bus + * @li pci_express + * @li platform + * @li pnp + * @li rtc + * @li scsi + * @li scsi_device + * @li scsi_disk + * @li scsi_generic + * @li scsi_host + * @li serio + * @li sound + * @li thermal + * @li tty + * @li usb + * @li usb_device + * @li vc + * @li vtconsole + * + * These are the devtypes of udev. + * @li atapi + * @li audio + * @li block + * @li cd + * @li char + * @li disk + * @li floppy + * @li generic + * @li hid + * @li hub + * @li media + * @li optical + * @li printer + * @li rbc + * @li scsi + * @li storage + * @li tape + * @li video + */ +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup udev + * @typedef Eeze_Udev_Event + * @enum Eeze_Udev_Event + * @brief Flags for watch events + * + * These events are used to specify the events to watch in a + * #Eeze_Udev_Watch. They can be ORed together. + *@{ + */ +typedef enum +{ + /** - No event specified */ + EEZE_UDEV_EVENT_NONE = 0xf0, + /** - Device added */ + EEZE_UDEV_EVENT_ADD = (1 << 1), + /** - Device removed */ + EEZE_UDEV_EVENT_REMOVE = (1 << 2), + /** - Device changed */ + EEZE_UDEV_EVENT_CHANGE = (1 << 3), + /** - Device has come online */ + EEZE_UDEV_EVENT_ONLINE = (1 << 4), + /** - Device has gone offline */ + EEZE_UDEV_EVENT_OFFLINE = (1 << 5) +} Eeze_Udev_Event; +/** @} */ + +/** + * @addtogroup udev udev + * @typedef Eeze_Udev_Type Eeze_Udev_Type + * @enum Eeze_Udev_Type + * @brief Convenience types to simplify udev access. + * + * These types allow easy access to certain udev device types. They + * may only be used in specified functions. + * + * @{ + */ +/*FIXME: these probably need to be bitmasks with categories*/ +typedef enum +{ + /** - No type */ + EEZE_UDEV_TYPE_NONE, + /** - Keyboard device */ + EEZE_UDEV_TYPE_KEYBOARD, + /** - Mouse device */ + EEZE_UDEV_TYPE_MOUSE, + /** - Touchpad device */ + EEZE_UDEV_TYPE_TOUCHPAD, + /** - Mountable drive */ + EEZE_UDEV_TYPE_DRIVE_MOUNTABLE, + /** - Internal drive */ + EEZE_UDEV_TYPE_DRIVE_INTERNAL, + /** - Removable drive */ + EEZE_UDEV_TYPE_DRIVE_REMOVABLE, + /** - cd drive */ + EEZE_UDEV_TYPE_DRIVE_CDROM, + /** - AC adapter */ + EEZE_UDEV_TYPE_POWER_AC, + /** - Battery */ + EEZE_UDEV_TYPE_POWER_BAT, + /** - Temperature sensor */ + EEZE_UDEV_TYPE_IS_IT_HOT_OR_IS_IT_COLD_SENSOR, + /** - Network devices */ + EEZE_UDEV_TYPE_NET, + /** - WebCam */ + EEZE_UDEV_TYPE_V4L, + /** - Bluetooth */ + EEZE_UDEV_TYPE_BLUETOOTH, + /** - Joystick + * @since 1.7 + */ + EEZE_UDEV_TYPE_JOYSTICK +} Eeze_Udev_Type; +/**@}*/ + +struct Eeze_Udev_Watch; + +/** + * @addtogroup watch + * @typedef Eeze_Udev_Watch Eeze_Udev_Watch + * @brief Opaque structure to hold data for a udev watch + */ +typedef struct Eeze_Udev_Watch Eeze_Udev_Watch; + +#define EEZE_VERSION_MAJOR 1 +#define EEZE_VERSION_MINOR 7 + + typedef struct _Eeze_Version + { + int major; + int minor; + int micro; + int revision; + } Eeze_Version; + + EAPI extern Eeze_Version *eeze_version; + +/** + * @addtogroup watch + * @typedef Eeze_Udev_Watch_Cb Eeze_Udev_Watch_Cb + * @brief Callback type for use with #Eeze_Udev_Watch + */ +typedef void(*Eeze_Udev_Watch_Cb)(const char *, Eeze_Udev_Event, void *, Eeze_Udev_Watch *); + + +/** + * Initialize the eeze library. + * @return The number of times the function has been called, or -1 on failure. + * + * This function should be called prior to using any eeze functions, and MUST + * be called prior to using any udev functions to avoid a segv. + * + * @ingroup main + */ +EAPI int eeze_init(void); + +/** + * Shut down the eeze library. + * @return The number of times the eeze_init has been called, or -1 when + * all occurrences of eeze have been shut down. + * + * This function should be called when no further eeze functions will be called. + * + * @ingroup main + */ +EAPI int eeze_shutdown(void); + + /** + * @addtogroup find Find + * + * These are functions which find/supplement lists of devices. + * + * @ingroup udev + * + * @{ + */ + +/** + * Returns a stringshared list of all syspaths that are (or should be) the same + * device as the device pointed at by @p syspath. + * + * @param syspath The syspath of the device to find matches for + * @return All devices which are the same as the one passed + */ +EAPI Eina_List *eeze_udev_find_similar_from_syspath(const char *syspath); + +/** + * Updates a list of all syspaths that are (or should be) the same + * device. + * + * @param list The list of devices to update + * @return The updated list + * + * This function will update @p list to include all devices matching + * devices with syspaths currently stored in @p list. All strings are + * stringshared. + * + * @note This is an expensive call, do not use it unless you must. + */ +EAPI Eina_List *eeze_udev_find_unlisted_similar(Eina_List *list); + +/** + * Find a list of devices by a sysattr (and, optionally, a value of that sysattr). + * + * @param sysattr The attribute to find + * @param value Optional: the value that the attribute should have + * + * @return A stringshared list of the devices found with the attribute + * + * @ingroup find + */ +EAPI Eina_List *eeze_udev_find_by_sysattr(const char *sysattr, const char *value); + +/** + * Find devices using an #Eeze_Udev_Type and/or a name. + * + * @param type An #Eeze_Udev_Type or 0 + * @param name A filter for the device name or @c NULL + * @return A stringshared Eina_List of matched devices or @c NULL on failure + * + * Return a list of syspaths (/sys/$syspath) for matching udev devices. + */ +EAPI Eina_List *eeze_udev_find_by_type(Eeze_Udev_Type type, const char *name); + +/** + * A more advanced find, allows finds using udev properties. + * + * @param subsystem The udev subsystem to filter by, or @c NULL + * @param type "ID_INPUT_KEY", "ID_INPUT_MOUSE", "ID_INPUT_TOUCHPAD", @c NULL, etc + * @param name A filter for the device name, or @c NULL + * @return A stringshared Eina_List* of matched devices or @c NULL on failure + * + * Return a list of syspaths (/sys/$syspath) for matching udev devices. + * Requires at least one filter. + */ +EAPI Eina_List *eeze_udev_find_by_filter(const char *subsystem, const char *type, const char *name); + /** + * @} + */ + + /** + * @addtogroup syspath Syspath + * + * These are functions which interact with the syspath (/sys/$PATH) of + * a device. + * + * @ingroup udev + * + * @{ + */ + +/** + * Get the syspath of a device from the /dev/ path. + * + * @param devpath The /dev/ path of the device + * @return A stringshared char* which corresponds to the /sys/ path of the device or @c NULL on failure + * + * Takes "/dev/path" and returns the corresponding /sys/ path (without the "/sys/") + */ +EAPI const char *eeze_udev_devpath_get_syspath(const char *devpath); + +/** + * Find the root device of a device from its syspath. + * + * @param syspath The syspath of a device, with or without "/sys/" + * @return The syspath of the parent device + * + * Return a stringshared syspath (/sys/$syspath) for the parent device. + */ +EAPI const char *eeze_udev_syspath_get_parent(const char *syspath); + +/** + * Returns a list of all parent device syspaths for @p syspath. + * + * @param syspath The device to find parents of + * @return A stringshared list of the parent devices of @p syspath + */ +EAPI Eina_List *eeze_udev_syspath_get_parents(const char *syspath); + +/** + * Get the /dev/ path from the /sys/ path. + * + * @param syspath The /sys/ path with or without the /sys/ + * @return A stringshared char* with the /dev/ path or @c NULL on failure + * + * Takes /sys/$PATH and turns it into the corresponding "/dev/x/y". + */ +EAPI const char *eeze_udev_syspath_get_devpath(const char *syspath); + +/** + * Get the /dev/ name from the /sys/ path. + * + * @param syspath The /sys/ path with or without the /sys/ + * @return A stringshared char* of the device name without the /dev/ path, or @c NULL on failure + * + * Takes /sys/$PATH and turns it into the corresponding /dev/x/"y". + */ +EAPI const char *eeze_udev_syspath_get_devname(const char *syspath); + +/** + * Get the subsystem of a device from the /sys/ path. + * + * @param syspath The /sys/ path with or without the /sys/ + * @return A stringshared char* with the subsystem of the device or @c NULL on failure + * + * Takes /sys/$PATH and returns the corresponding device subsystem, + * such as "input" for keyboards/mice. + */ +EAPI const char *eeze_udev_syspath_get_subsystem(const char *syspath); + +/** + * Get the property value of a device from the /sys/ path. + * + * @param syspath The /sys/ path with or without the /sys/ + * @param property The property to get; full list of these is a FIXME + * @return A stringshared char* with the property or @c NULL on failure + */ +EAPI const char *eeze_udev_syspath_get_property(const char *syspath, const char *property); + +/** + * Get the sysattr value of a device from the /sys/ path. + * + * @param syspath The /sys/ path with or without the /sys/ + * @param sysattr The sysattr to get; full list of these is a FIXME + * @return A stringshared char* with the sysattr or @c NULL on failure + */ +EAPI const char *eeze_udev_syspath_get_sysattr(const char *syspath, const char *sysattr); + +/** + * Checks whether the device is a mouse. + * + * @param syspath The /sys/ path with or without the /sys/ + * @return If true, the device is a mouse + */ +EAPI Eina_Bool eeze_udev_syspath_is_mouse(const char *syspath); + +/** + * Checks whether the device is a keyboard. + * + * @param syspath The /sys/ path with or without the /sys/ + * @return If true, the device is a keyboard + */ +EAPI Eina_Bool eeze_udev_syspath_is_kbd(const char *syspath); + +/** + * Checks whether the device is a touchpad. + * + * @param syspath The /sys/ path with or without the /sys/ + * @return If true, the device is a touchpad + */ +EAPI Eina_Bool eeze_udev_syspath_is_touchpad(const char *syspath); + +/** + * Checks whether the device is a joystick. + * + * @param syspath The /sys/ path with or without the /sys/ + * @return If true, the device is a joystick + * @since 1.7 + */ +EAPI Eina_Bool eeze_udev_syspath_is_joystick(const char *syspath); + /** + * @} + */ + + /** + * @addtogroup walks Walks + * + * These are functions which walk up the device chain. + * + * @ingroup udev + * + * @{ + */ + +/** + * Walks up the device chain starting at @p syspath, + * checking each device for @p sysattr with (optional) @p value. + * + * @param syspath The /sys/ path of the device to start at, with or without the /sys/ + * @param sysattr The attribute to find + * @param value OPTIONAL: The value that @p sysattr should have, or @c NULL + * + * @return If the sysattr (with value) is found, returns TRUE. Else, false. + */ +EAPI Eina_Bool eeze_udev_walk_check_sysattr(const char *syspath, const char *sysattr, const char *value); + +/** + * Walks up the device chain starting at @p syspath, + * checking each device for @p sysattr, and returns the value if found. + * + * @param syspath The /sys/ path of the device to start at, with or without the /sys/ + * @param sysattr The attribute to find + * + * @return The stringshared value of @p sysattr if found, or @c NULL + */ +EAPI const char *eeze_udev_walk_get_sysattr(const char *syspath, const char *sysattr); + /** + * @} + */ + + /** + * @addtogroup watch Watch + * + * @brief These are functions which monitor udev for events. + * + * Eeze watches are simple: you specify a type of device to watch (or all devices), some events (or all) to watch for, a callback, + * and some data, and then udev watches those device types for events of the type you specified. Your callback is called with a + * syspath of the triggering device and the event that happened to the device, along with the data you associated with the watch and + * the watch object itself in case you want to stop the watch easily in a callback. + * + * @ingroup udev + * + * @{ + */ + +/** + * Add a watch for a device type + * + * @param type The #Eeze_Udev_Type to watch + * @param event The events to watch; an OR list of #Eeze_Udev_Event (ie (#EEZE_UDEV_EVENT_ADD | #EEZE_UDEV_EVENT_REMOVE)), or 0 for all events + * @param cb The function to call when the watch receives data of type #Eeze_Udev_Watch_Cb + * @param user_data Data to pass to the callback function + * + * @return A watch struct for the watch type specified, or @c NULL on failure + * + * Eeze watches will monitor udev for changes of type(s) @p event to devices of type @p type. When these changes occur, the stringshared + * syspath of the device will be sent to function @p func, along with the bitmask of the event type which can be detected through + * binary &. + */ +EAPI Eeze_Udev_Watch *eeze_udev_watch_add(Eeze_Udev_Type type, int event, Eeze_Udev_Watch_Cb cb, void *user_data); + +/** + * Deletes a watch. + * + * @param watch An Eeze_Udev_Watch object + * @return The data originally associated with the watch, or @c NULL + * + * Deletes a watch, closing file descriptors and freeing related udev memory. + */ +EAPI void *eeze_udev_watch_del(Eeze_Udev_Watch *watch); + /** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/Eeze_Disk.h b/src/lib/Eeze_Disk.h new file mode 100644 index 0000000..36079b3 --- /dev/null +++ b/src/lib/Eeze_Disk.h @@ -0,0 +1,567 @@ +#ifndef EEZE_DISK_H +#define EEZE_DISK_H + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +#else +# define EAPI +#endif + +#include <Eina.h> +#include <Ecore.h> + +/** + * @file Eeze_Disk.h + * @brief Disk manipulation + * @since 1.1 + * + * Eeze disk functions allow you to quickly and efficiently manipulate disks + * through simple function calls. + * + * @addtogroup disk Disk + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @enum Eeze_Disk_Type + * @since 1.1 + * + * All disk types known to Eeze. + */ +typedef enum +{ + EEZE_DISK_TYPE_UNKNOWN = 0, /**< type could not be determined */ + EEZE_DISK_TYPE_INTERNAL = (1 << 0), /**< internal drive */ + EEZE_DISK_TYPE_CDROM = (1 << 1), /**< cdrom drive */ + EEZE_DISK_TYPE_USB = (1 << 2), /**< usb drive */ + EEZE_DISK_TYPE_FLASH = (1 << 3) /**< flash disk */ +} Eeze_Disk_Type; + +/** + * @enum Eeze_Mount_Opts + * @since 1.1 + * + * All mount options known to Eeze. + */ +typedef enum +{ +#define EEZE_DISK_MOUNTOPT_DEFAULTS (EEZE_DISK_MOUNTOPT_UTF8 | EEZE_DISK_MOUNTOPT_NOEXEC | EEZE_DISK_MOUNTOPT_NOSUID) + EEZE_DISK_MOUNTOPT_LOOP = (1 << 1), + EEZE_DISK_MOUNTOPT_UTF8 = (1 << 2), + EEZE_DISK_MOUNTOPT_NOEXEC = (1 << 3), + EEZE_DISK_MOUNTOPT_NOSUID = (1 << 4), + EEZE_DISK_MOUNTOPT_REMOUNT = (1 << 5), + EEZE_DISK_MOUNTOPT_UID = (1 << 6), /**< use current user's uid */ + EEZE_DISK_MOUNTOPT_NODEV = (1 << 7) /**< @since 1.7 */ +} Eeze_Mount_Opts; + + +EAPI extern int EEZE_EVENT_DISK_MOUNT; +EAPI extern int EEZE_EVENT_DISK_UNMOUNT; +EAPI extern int EEZE_EVENT_DISK_EJECT; +EAPI extern int EEZE_EVENT_DISK_ERROR; + +typedef struct _Eeze_Event_Disk Eeze_Event_Disk_Mount; +typedef struct _Eeze_Event_Disk Eeze_Event_Disk_Unmount; +typedef struct _Eeze_Event_Disk Eeze_Event_Disk_Eject; + +/** + * @typedef Eeze_Disk + * @since 1.1 + * + * Handle for an Eeze Disk. + */ +typedef struct _Eeze_Disk Eeze_Disk; + +struct _Eeze_Event_Disk +{ + Eeze_Disk *disk; +}; + +/** + * @typedef Eeze_Event_Disk_Error + * @since 1.1 + * + * Contains the human readable error message. + */ +typedef struct _Eeze_Event_Disk_Error Eeze_Event_Disk_Error; + +struct _Eeze_Event_Disk_Error +{ + Eeze_Disk *disk; + const char *message; +}; + +/** + * @brief Use this function to determine whether your eeze is disk-capable + * + * Since applications will die if they run/compile against a function that doesn't exist, + * if your application successfully runs/compiles with this function then you have eeze_disk. + * @since 1.1 + */ +EAPI void eeze_disk_function(void); + +/** + * @brief Return whether mount support is available in eeze + * + * Use this function to determine whether your Eeze library was compiled with a mount + * binary available. + * @since 1.1 + */ +EAPI Eina_Bool eeze_disk_can_mount(void); + +/** + * @brief Return whether unmount support is available in eeze + * + * Use this function to determine whether your Eeze library was compiled with an unmount + * binary available. + * @since 1.1 + */ +EAPI Eina_Bool eeze_disk_can_unmount(void); + +/** + * @brief Return whether eject support is available in eeze + * + * Use this function to determine whether your Eeze library was compiled with an eject + * binary available. + * @since 1.1 + */ +EAPI Eina_Bool eeze_disk_can_eject(void); + +/** + * @brief Create a new disk object from a /sys/ path or /dev/ path + * @param path The /sys/ or /dev path of the disk; CANNOT be @c NULL. + * @return The new disk object + * + * This function creates a new #Eeze_Disk from @p path. Note that this function + * does the minimal amount of work in order to save memory, and udev info about the disk + * is not retrieved in this call. + * @since 1.1 + */ +EAPI Eeze_Disk *eeze_disk_new(const char *path); + +/** + * @brief Create a new disk object from a mount point + * @param mount_point The mount point of the disk; CANNOT be @c NULL + * @return The new disk object + * + * This function creates a new #Eeze_Disk from @p mount_point. Note that this function + * does the minimal amount of work in order to save memory, and udev info about the disk + * is not retrieved in this call. If the disk is not currently mounted, it must have an entry + * in /etc/fstab. + * @since 1.1 + */ +EAPI Eeze_Disk *eeze_disk_new_from_mount(const char *mount_point); + +/** + * @brief Frees a disk object + * @param disk The disk object to free + * + * This call frees an #Eeze_Disk. Once freed, the disk can no longer be used. + * @since 1.1 + */ +EAPI void eeze_disk_free(Eeze_Disk *disk); + +/** + * @brief Retrieve all disk information + * @param disk + * + * Use this function to retrieve all of a disk's information at once, then use + * a "get" function to retrieve the value. Data retrieved in this call is cached, + * meaning that subsequent calls will return immediately without performing any work. + * @since 1.1 + */ +EAPI void eeze_disk_scan(Eeze_Disk *disk); + +/** + * @brief Associate data with a disk + * @param disk The disk + * @param data The data + * + * Data can be associated with @p disk with this function. + * @see eeze_disk_data_get + * @since 1.1 + */ +EAPI void eeze_disk_data_set(Eeze_Disk *disk, void *data); + +/** + * @brief Retrieve data previously associated with a disk + * @param disk The disk + * @return The data + * + * Data that has been previously associated with @p disk + * is returned with this function. + * @see eeze_disk_data_set + * @since 1.1 + */ +EAPI void *eeze_disk_data_get(Eeze_Disk *disk); + +/** + * @brief Return the /sys/ path of a disk + * @param disk The disk + * @return The /sys/ path + * + * This retrieves the /sys/ path that udev associates with @p disk. + * @since 1.1 + */ +EAPI const char *eeze_disk_syspath_get(Eeze_Disk *disk); + +/** + * @brief Return the /dev/ path of a disk + * @param disk The disk + * @return The /dev/ path + * + * This retrieves the /dev/ path that udev has created a device node at for @p disk. + * @since 1.1 + */ +EAPI const char *eeze_disk_devpath_get(Eeze_Disk *disk); + +/** + * @brief Return the filesystem of the disk (if known) + * @param disk The disk + * @return The filesystem type + * + * This retrieves the filesystem that the disk is using, or @c NULL if unknown. + * @since 1.1 + */ +EAPI const char *eeze_disk_fstype_get(Eeze_Disk *disk); + +/** + * @brief Return the manufacturing vendor of the disk + * @param disk The disk + * @return The vendor + * + * This retrieves the vendor which manufactured the disk, or @c NULL if unknown. + * @since 1.1 + */ +EAPI const char *eeze_disk_vendor_get(Eeze_Disk *disk); + +/** + * @brief Return the model of the disk + * @param disk The disk + * @return The model + * + * This retrieves the model of the disk, or @c NULL if unknown. + * @since 1.1 + */ +EAPI const char *eeze_disk_model_get(Eeze_Disk *disk); + +/** + * @brief Return the serial number of the disk + * @param disk The disk + * @return The serial number + * + * This retrieves the serial number the disk, or @c NULL if unknown. + * @since 1.1 + */ +EAPI const char *eeze_disk_serial_get(Eeze_Disk *disk); + +/** + * @brief Return the UUID of the disk + * @param disk The disk + * @return The UUID + * + * This retrieves the UUID of the disk, or @c NULL if unknown. + * A UUID is a 36 character (hopefully) unique identifier which can + * be used to store persistent information about a disk. + * @since 1.1 + */ +EAPI const char *eeze_disk_uuid_get(Eeze_Disk *disk); + +/** + * @brief Return the label of the disk + * @param disk The disk + * @return The label + * + * This retrieves the label (name) of the disk, or @c NULL if unknown. + * @since 1.1 + */ +EAPI const char *eeze_disk_label_get(Eeze_Disk *disk); + +/** + * @brief Return the #Eeze_Disk_Type of the disk + * @param disk The disk + * @return The type + * + * This retrieves the #Eeze_Disk_Type of the disk. This call is useful for determining + * the bus that the disk is connected through. + * @since 1.1 + */ +EAPI Eeze_Disk_Type eeze_disk_type_get(Eeze_Disk *disk); + +/** + * @brief Return whether the disk is removable + * @param disk The disk + * @return @c EINA_TRUE if removable, @c EINA_FALSE otherwise. + * @since 1.1 + */ +EAPI Eina_Bool eeze_disk_removable_get(Eeze_Disk *disk); + + +/** + * @brief Return the mount state of a disk + * @param disk The disk + * @return The mount state + * + * This returns the mounted state of the disk. @c EINA_TRUE if mounted, + * @c EINA_FALSE otherwise. + * @since 1.1 + */ +EAPI Eina_Bool eeze_disk_mounted_get(Eeze_Disk *disk); + +/** + * @brief Get the previously set mount wrapper for a disk + * @param disk The disk + * @return The wrapper, or @c NULL on failure. + * + * This returns the wrapper previously set with eeze_disk_mount_wrapper_set + * @since 1.1 + */ +EAPI const char *eeze_disk_mount_wrapper_get(Eeze_Disk *disk); + +/** + * @brief Set a wrapper to run mount commands with + * @param disk The disk to wrap mount commands for + * @param wrapper The wrapper executable + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * Use this function to set up a wrapper for running mount/umount commands. The wrapper must + * NOT use any of the standard mount/umount error code return values, and it must return 0 on success. + * Note that this function will call stat() on @p wrapper if not @c NULL to test for existence. + * @since 1.1 + */ +EAPI Eina_Bool eeze_disk_mount_wrapper_set(Eeze_Disk *disk, const char *wrapper); + +/** + * @brief Begin a mount operation on the disk + * @param disk The disk + * @return @c EINA_TRUE if the operation was started, @c EINA_FALSE otherwise. + * + * This call is used to begin a mount operation on @p disk. The operation will + * run asynchronously in a pipe, emitting an EEZE_EVENT_DISK_MOUNT event with the disk object + * as its event on completion. If any errors are encountered, they will automatically logged + * to the eeze_disk domain and an EEZE_EVENT_DISK_ERROR event will be generated with an #Eeze_Event_Disk_Error + * struct as its event. + * + * NOTE: The return value of this function does not in any way reflect the mount state of a disk. + * @since 1.1 + */ +EAPI Eina_Bool eeze_disk_mount(Eeze_Disk *disk); + +/** + * @brief Begin an unmount operation on the disk + * @param disk The disk + * @return @c EINA_TRUE if the operation was started, @c EINA_FALSE otherwise. + * + * This call is used to begin an unmount operation on @p disk. The operation will + * run asynchronously in a pipe, emitting an EEZE_EVENT_DISK_UNMOUNT event with the disk object + * as its event on completion. If any errors are encountered, they will automatically logged + * to the eeze_disk domain and an EEZE_EVENT_DISK_ERROR event will be generated with + * an #Eeze_Event_Disk_Error struct as its event. + * + * NOTE: The return value of this function does not in any way reflect the mount state of a disk. + * @since 1.1 + */ +EAPI Eina_Bool eeze_disk_unmount(Eeze_Disk *disk); + +/** + * @brief Begin an eject operation on the disk + * @param disk The disk + * @return @c EINA_TRUE if the operation was started, @c EINA_FALSE otherwise. + * + * This call is used to begin an eject operation on @p disk. The operation will + * run asynchronously in a pipe, emitting an EEZE_EVENT_DISK_EJECT event with the disk object + * as its event on completion. If any errors are encountered, they will automatically logged + * to the eeze_disk domain and an EEZE_EVENT_DISK_ERROR event will be generated with + * an #Eeze_Event_Disk_Error struct as its event. + * + * NOTE: The return value of this function does not in any way reflect the mount state of a disk. + * @since 1.1 + */ +EAPI Eina_Bool eeze_disk_eject(Eeze_Disk *disk); +/** + * @brief Cancel a pending operation on the disk + * @param disk The disk + * + * This function cancels the current pending operation on @p disk which was previously + * started with eeze_disk_mount or eeze_disk_unmount. + * @since 1.1 + */ +EAPI void eeze_disk_cancel(Eeze_Disk *disk); + +/** + * @brief Return the mount point of a disk + * @param disk The disk + * @return The mount point + * + * This function returns the mount point associated with @p disk. + * Note that to determine whether the disk is actually mounted, eeze_disk_mounted_get should be used. + * @since 1.1 + */ +EAPI const char *eeze_disk_mount_point_get(Eeze_Disk *disk); + +/** + * @brief Set the mount point of a disk + * @param disk The disk + * @param mount_point The mount point + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * This function sets the mount point associated with @p disk. + * Note that to determine whether the disk is actually mounted, eeze_disk_mounted_get should be used. + * Also note that this function cannot be used while the disk is mounted to avoid losing the current mount point. + * @since 1.1 + */ +EAPI Eina_Bool eeze_disk_mount_point_set(Eeze_Disk *disk, const char *mount_point); + +/** + * @brief Set the mount options using flags + * @param disk The disk + * @param opts An ORed set of #Eeze_Mount_Opts + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * This function replaces the current mount opts of a disk with the ones in @p opts. + * @since 1.1 + */ +EAPI Eina_Bool eeze_disk_mountopts_set(Eeze_Disk *disk, unsigned long opts); + +/** + * @brief Get the flags of a disk's current mount options + * @param disk The disk + * @return An ORed set of #Eeze_Mount_Opts, 0 on failure + * + * This function returns the current mount opts of a disk. + * @since 1.1 + */ +EAPI unsigned long eeze_disk_mountopts_get(Eeze_Disk *disk); + + +/** + * @brief Begin watching mtab and fstab + * @return @c EINA_TRUE if watching was started, @c EINA_FALSE otherwise. + * + * This function creates inotify watches on /etc/mtab and /etc/fstab and watches + * them for changes. This function should be used when expecting a lot of disk + * mounting/unmounting while you need disk data since it will automatically update + * certain necessary data instead of waiting. + * @see eeze_mount_mtab_scan, eeze_mount_fstab_scan + * @since 1.1 + */ +EAPI Eina_Bool eeze_mount_tabs_watch(void); + +/** + * @brief Stop watching /etc/fstab and /etc/mtab + * + * This function stops watching fstab and mtab. Data obtained previously will be saved. + * @since 1.1 + */ +EAPI void eeze_mount_tabs_unwatch(void); + +/** + * @brief Scan /etc/mtab a single time + * @return @c EINA_TRUE if mtab could be scanned, @c EINA_FALSE otherwise. + * + * This function is used to perform a single scan on /etc/mtab. It is used to gather + * information about mounted filesystems which can then be used with your #Eeze_Disk objects + * where appropriate. These files will automatically be scanned any time a mount point or mount state + * is requested unless eeze_mount_tabs_watch has been called previously, in which case data is stored for + * use. + * If this function is called after eeze_mount_tabs_watch, @c EINA_TRUE will be returned. + * @see eeze_mount_tabs_watch, eeze_mount_fstab_scan + * @since 1.1 + */ +EAPI Eina_Bool eeze_mount_mtab_scan(void); + +/** + * @brief Scan /etc/fstab a single time + * @return @c EINA_TRUE if mtab could be scanned, @c EINA_FALSE otherwise. + * + * This function is used to perform a single scan on /etc/fstab. It is used to gather + * information about mounted filesystems which can then be used with your #Eeze_Disk objects + * where appropriate. These files will automatically be scanned any time a mount point or mount state + * is requested unless eeze_mount_tabs_watch has been called previously, in which case data is stored for + * use. + * If this function is called after eeze_mount_tabs_watch, @c EINA_TRUE will be returned. + * @see eeze_mount_tabs_watch, eeze_mount_mtab_scan + * @since 1.1 + */ +EAPI Eina_Bool eeze_mount_fstab_scan(void); + +/** + * @brief Get the property value of a disk + * + * @param disk The disk + * @param property The property to get; full list of these is a FIXME + * @return A stringshared char* with the property or @c NULL on failure. + * @since 1.1 + */ + +EAPI const char *eeze_disk_udev_get_property(Eeze_Disk *disk, const char *property); + +/** + * @brief Get the sysattr value of a disk. + * + * @param disk The disk + * @param sysattr The sysattr to get; full list of these is a FIXME + * @return A stringshared char* with the sysattr or @c NULL on failure. + * @since 1.1 + */ + +EAPI const char *eeze_disk_udev_get_sysattr(Eeze_Disk *disk, const char *sysattr); + +/** + * Find the root device of a disk. + * + * @param disk The disk + * @return The syspath of the parent device + * + * Return a stringshared syspath (/sys/$syspath) for the parent device. + * @since 1.1 + */ +EAPI const char *eeze_disk_udev_get_parent(Eeze_Disk *disk); + +/** + * Walks up the device chain using the device from @p disk, + * checking each device for @p sysattr with (optional) @p value. + * + * @param disk The disk to walk + * @param sysattr The attribute to find + * @param value OPTIONAL: The value that @p sysattr should have, or @c NULL. + * + * @return If the sysattr (with value) is found, returns @c EINA_TRUE, + * @c EINA_FALSE otherwise. + * @since 1.1 + */ +EAPI Eina_Bool eeze_disk_udev_walk_check_sysattr(Eeze_Disk *disk, const char *sysattr, const char *value); + +/** + * @brief Walks up the device chain of @p disk + * checking each device for @p sysattr and returns the value if found. + * + * @param disk The disk + * @param sysattr The attribute to find + * + * @return The stringshared value of @p sysattr if found, or @c NULL. + * @since 1.1 + */ +EAPI const char *eeze_disk_udev_walk_get_sysattr(Eeze_Disk *disk, const char *sysattr); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ +#endif diff --git a/src/lib/Eeze_Net.h b/src/lib/Eeze_Net.h new file mode 100644 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..b14e44d --- /dev/null +++ b/src/lib/Makefile.am @@ -0,0 +1,43 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = @EEZE_CFLAGS@ + +includes_HEADERS = Eeze.h Eeze_Net.h + +libeeze_la_SOURCES = \ +eeze_main.c \ +eeze_net.c \ +eeze_net_private.h \ +eeze_udev_find.c \ +eeze_udev_private.h \ +eeze_udev_private.c \ +eeze_udev_syspath.c \ +eeze_udev_walk.c \ +eeze_udev_watch.c + +if HAVE_EEZE_MOUNT + AM_CFLAGS = @EEZE_CFLAGS@ @LIBMOUNT_CFLAGS@ @ECORE_FILE_CFLAGS@ + libeeze_la_SOURCES += eeze_disk.c eeze_disk_udev.c eeze_disk_mount.c eeze_disk_private.h +if OLD_LIBMOUNT + libeeze_la_SOURCES += eeze_disk_libmount_old.c +else +if NEW_LIBMOUNT + libeeze_la_SOURCES += eeze_disk_libmount_new.c +else + libeeze_la_SOURCES += eeze_disk_libmount.c +endif +endif + includes_HEADERS += Eeze_Disk.h +else + AM_CFLAGS = @EEZE_CFLAGS@ +endif + +lib_LTLIBRARIES = libeeze.la +includesdir = $(includedir)/eeze-@VMAJ@ + +if HAVE_EEZE_MOUNT + libeeze_la_LIBADD = @EEZE_LIBS@ @LIBMOUNT_LIBS@ @ECORE_FILE_LIBS@ +else + libeeze_la_LIBADD = @EEZE_LIBS@ +endif +libeeze_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@ diff --git a/src/lib/eeze_disk.c b/src/lib/eeze_disk.c new file mode 100644 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..885f313 --- /dev/null +++ b/src/lib/eeze_disk_libmount.c @@ -0,0 +1,495 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef USE_UNSTABLE_LIBMOUNT_API +# define USE_UNSTABLE_LIBMOUNT_API 1 +#endif + +#include <Ecore.h> +#include <Eeze.h> +#include <Eeze_Disk.h> +#include <libmount.h> +#include <unistd.h> + +#include "eeze_udev_private.h" +#include "eeze_disk_private.h" + +/* + * + * PRIVATE + * + */ + +static struct libmnt_optmap eeze_optmap[] = +{ + { "loop[=]", EEZE_DISK_MOUNTOPT_LOOP, 0 }, + { "utf8", EEZE_DISK_MOUNTOPT_UTF8, 0 }, + { "noexec", EEZE_DISK_MOUNTOPT_NOEXEC, 0 }, + { "nosuid", EEZE_DISK_MOUNTOPT_NOSUID, 0 }, + { "remount", EEZE_DISK_MOUNTOPT_REMOUNT, 0 }, + { "uid[=]", EEZE_DISK_MOUNTOPT_UID, 0 }, + { "nodev", EEZE_DISK_MOUNTOPT_NODEV, 0 }, + { NULL, 0, 0 } +}; +typedef struct libmnt_table libmnt_table; +typedef struct libmnt_lock libmnt_lock; +typedef struct libmnt_fs libmnt_fs; +typedef struct libmnt_cache libmnt_cache; +static Ecore_File_Monitor *_mtab_mon = NULL; +static Ecore_File_Monitor *_fstab_mon = NULL; +static Eina_Bool _watching = EINA_FALSE; +static Eina_Bool _mtab_scan_active = EINA_FALSE; +static Eina_Bool _mtab_locked = EINA_FALSE; +static Eina_Bool _fstab_scan_active = EINA_FALSE; +static libmnt_cache *_eeze_mount_mtab_cache = NULL; +static libmnt_cache *_eeze_mount_fstab_cache = NULL; +static libmnt_table *_eeze_mount_mtab = NULL; +static libmnt_table *_eeze_mount_fstab = NULL; +static libmnt_lock *_eeze_mtab_lock = NULL; +extern Eina_List *_eeze_disks; + +static libmnt_table *_eeze_mount_tab_parse(const char *filename); +static void _eeze_mount_tab_watcher(void *data, Ecore_File_Monitor *mon __UNUSED__, Ecore_File_Event event __UNUSED__, const char *path); + +static Eina_Bool +_eeze_mount_lock_mtab(void) +{ +// DBG("Locking mlock: %s", mnt_lock_get_linkfile(_eeze_mtab_lock)); + if (EINA_LIKELY(access("/etc/mtab", W_OK))) + { + INF("Insufficient privs for mtab lock, continuing without lock"); + return EINA_TRUE; + } + if (mnt_lock_file(_eeze_mtab_lock)) + { + ERR("Couldn't lock mtab!"); + return EINA_FALSE; + } + _mtab_locked = EINA_TRUE; + return EINA_TRUE; +} + +static void +_eeze_mount_unlock_mtab(void) +{ +// DBG("Unlocking mlock: %s", mnt_lock_get_linkfile(_eeze_mtab_lock)); + if (_mtab_locked) mnt_unlock_file(_eeze_mtab_lock); + _mtab_locked = EINA_FALSE; +} + + +static int +_eeze_mount_tab_parse_errcb(libmnt_table *tab __UNUSED__, const char *filename, int line) +{ + ERR("%s:%d: could not parse line!", filename, line); /* most worthless error reporting ever. */ + return -1; +} + +/* + * I could use mnt_new_table_from_file() but this way gives much more detailed output + * on failure so why not + */ +static libmnt_table * +_eeze_mount_tab_parse(const char *filename) +{ + libmnt_table *tab; + + if (!(tab = mnt_new_table())) return NULL; + if (mnt_table_set_parser_errcb(tab, _eeze_mount_tab_parse_errcb)) + { + ERR("Alloc!"); + mnt_free_table(tab); + return NULL; + } + + if (!mnt_table_parse_file(tab, filename)) + return tab; + + mnt_free_table(tab); + return NULL; +} + +static void +_eeze_mount_tab_watcher(void *data, Ecore_File_Monitor *mon __UNUSED__, Ecore_File_Event event __UNUSED__, const char *path) +{ + libmnt_table *bak; + + if ( + ((_mtab_scan_active) && (data)) || /* mtab has non-null data to avoid needing strcmp */ + ((_fstab_scan_active) && (!data)) + ) + /* prevent scans from triggering a scan */ + return; + + bak = _eeze_mount_mtab; + if (data) + if (!_eeze_mount_lock_mtab()) + { /* FIXME: maybe queue job here? */ + ERR("Losing events..."); + return; + } + _eeze_mount_mtab = _eeze_mount_tab_parse(path); + if (data) + _eeze_mount_unlock_mtab(); + if (!_eeze_mount_mtab) + { + ERR("Could not parse %s! keeping old tab...", path); + goto error; + } + if (data) + { + Eina_List *l; + Eeze_Disk *disk; + + /* catch externally initiated mounts on existing disks by comparing known mount state to current state */ + EINA_LIST_FOREACH(_eeze_disks, l, disk) + { + Eina_Bool mounted; + + mounted = disk->mounted; + + if ((eeze_disk_libmount_mounted_get(disk) != mounted) && (!disk->mount_status)) + { + if (!mounted) + { + Eeze_Event_Disk_Mount *e; + e = malloc(sizeof(Eeze_Event_Disk_Mount)); + if (e) + { + e->disk = disk; + ecore_event_add(EEZE_EVENT_DISK_MOUNT, e, NULL, NULL); + } + } + else + { + Eeze_Event_Disk_Unmount *e; + e = malloc(sizeof(Eeze_Event_Disk_Unmount)); + if (e) + { + e->disk = disk; + ecore_event_add(EEZE_EVENT_DISK_UNMOUNT, e, NULL, NULL); + } + } + } + } + } + + mnt_free_table(bak); + if (data) + { + mnt_free_cache(_eeze_mount_mtab_cache); + _eeze_mount_mtab_cache = mnt_new_cache(); + mnt_table_set_cache(_eeze_mount_mtab, _eeze_mount_mtab_cache); + } + else + { + mnt_free_cache(_eeze_mount_fstab_cache); + _eeze_mount_fstab_cache = mnt_new_cache(); + mnt_table_set_cache(_eeze_mount_fstab, _eeze_mount_fstab_cache); + } + return; + +error: + mnt_free_table(_eeze_mount_mtab); + _eeze_mount_mtab = bak; +} + +/* + * + * INVISIBLE + * + */ + +Eina_Bool +eeze_libmount_init(void) +{ + if (_eeze_mtab_lock) + return EINA_TRUE; + if (!(_eeze_mtab_lock = mnt_new_lock("/etc/mtab", 0))) + return EINA_FALSE; + return EINA_TRUE; +} + +void +eeze_libmount_shutdown(void) +{ + if (_eeze_mount_fstab) + { + mnt_free_table(_eeze_mount_fstab); + mnt_free_cache(_eeze_mount_fstab_cache); + } + if (_eeze_mount_mtab) + { + mnt_free_table(_eeze_mount_mtab); + mnt_free_cache(_eeze_mount_mtab_cache); + } + eeze_mount_tabs_unwatch(); + if (!_eeze_mtab_lock) + return; + + mnt_unlock_file(_eeze_mtab_lock); + mnt_free_lock(_eeze_mtab_lock); + _eeze_mtab_lock = NULL; +} + +unsigned long +eeze_disk_libmount_opts_get(Eeze_Disk *disk) +{ + libmnt_fs *mnt; + const char *opts; + unsigned long f = 0; + + if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan()) + return 0; + + mnt = mnt_table_find_tag(_eeze_mount_mtab, "UUID", eeze_disk_uuid_get(disk), MNT_ITER_BACKWARD); + if (!mnt) + mnt = mnt_table_find_tag(_eeze_mount_fstab, "UUID", eeze_disk_uuid_get(disk), MNT_ITER_BACKWARD); + + if (!mnt) return 0; + + opts = mnt_fs_get_fs_options(mnt); + if (!opts) return 0; + if (!mnt_optstr_get_flags(opts, &f, eeze_optmap)) return 0; + return f; +} + +/* + * helper function to return whether a disk is mounted + */ +Eina_Bool +eeze_disk_libmount_mounted_get(Eeze_Disk *disk) +{ + libmnt_fs *mnt; + + if (!disk) + return EINA_FALSE; + + if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan()) + return EINA_FALSE; + + mnt = mnt_table_find_srcpath(_eeze_mount_mtab, eeze_disk_devpath_get(disk), MNT_ITER_BACKWARD); + if (!mnt) + { + disk->mounted = EINA_FALSE; + return EINA_FALSE; + } + + eina_stringshare_replace(&disk->mount_point, mnt_fs_get_target(mnt)); + disk->mounted = EINA_TRUE; + return EINA_TRUE; +} + + +/* + * helper function to return the device that is mounted at a mount point + */ +const char * +eeze_disk_libmount_mp_find_source(const char *mount_point) +{ + libmnt_fs *mnt; + + if (!mount_point) + return NULL; + + if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan()) + return NULL; + + mnt = mnt_table_find_target(_eeze_mount_mtab, mount_point, MNT_ITER_BACKWARD); + if (!mnt) + mnt = mnt_table_find_target(_eeze_mount_fstab, mount_point, MNT_ITER_BACKWARD); + + if (!mnt) + return NULL; + + return mnt_fs_get_source(mnt); +} + +/* + * helper function to return a mount point from a uuid + */ +const char * +eeze_disk_libmount_mp_lookup_by_uuid(const char *uuid) +{ + libmnt_fs *mnt; + + if (!uuid) + return NULL; + + if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan()) + return NULL; + + mnt = mnt_table_find_tag(_eeze_mount_fstab, "UUID", uuid, MNT_ITER_BACKWARD); + + if (!mnt) + return NULL; + + return mnt_fs_get_target(mnt); +} + +/* + * helper function to return a mount point from a label + */ +const char * +eeze_disk_libmount_mp_lookup_by_label(const char *label) +{ + libmnt_fs *mnt; + + if (!label) + return NULL; + + if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan()) + return NULL; + + mnt = mnt_table_find_tag(_eeze_mount_fstab, "LABEL", label, MNT_ITER_BACKWARD); + + if (!mnt) + return NULL; + + return mnt_fs_get_target(mnt); +} + +/* + * helper function to return a mount point from a /dev/ path + */ +const char * +eeze_disk_libmount_mp_lookup_by_devpath(const char *devpath) +{ + libmnt_fs *mnt; + + if (!devpath) + return NULL; + + if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan()) + return NULL; + + mnt = mnt_table_find_srcpath(_eeze_mount_mtab, devpath, MNT_ITER_BACKWARD); + if (!mnt) + mnt = mnt_table_find_srcpath(_eeze_mount_fstab, devpath, MNT_ITER_BACKWARD); + + if (!mnt) + return NULL; + + return mnt_fs_get_target(mnt); +} + +/* + * + * API + * + */ + +EAPI Eina_Bool +eeze_mount_tabs_watch(void) +{ + libmnt_table *bak; + + if (_watching) + return EINA_TRUE; + + if (!_eeze_mount_lock_mtab()) + return EINA_FALSE; + + bak = _eeze_mount_tab_parse("/etc/mtab"); + _eeze_mount_unlock_mtab(); + if (!bak) + goto error; + + mnt_free_table(_eeze_mount_mtab); + _eeze_mount_mtab = bak; + if (!(bak = _eeze_mount_tab_parse("/etc/fstab"))) + goto error; + + mnt_free_table(_eeze_mount_fstab); + _eeze_mount_fstab = bak; + + _eeze_mount_mtab_cache = mnt_new_cache(); + mnt_table_set_cache(_eeze_mount_mtab, _eeze_mount_mtab_cache); + + _eeze_mount_fstab_cache = mnt_new_cache(); + mnt_table_set_cache(_eeze_mount_fstab, _eeze_mount_fstab_cache); + + _mtab_mon = ecore_file_monitor_add("/etc/mtab", _eeze_mount_tab_watcher, (void*)1); + _fstab_mon = ecore_file_monitor_add("/etc/fstab", _eeze_mount_tab_watcher, NULL); + _watching = EINA_TRUE; + + return EINA_TRUE; + +error: + if (!_eeze_mount_mtab) + ERR("Could not parse /etc/mtab!"); + else + { + ERR("Could not parse /etc/fstab!"); + mnt_free_table(_eeze_mount_mtab); + } + return EINA_FALSE; +} + +EAPI void +eeze_mount_tabs_unwatch(void) +{ + if (!_watching) + return; + + ecore_file_monitor_del(_mtab_mon); + _mtab_mon = NULL; + ecore_file_monitor_del(_fstab_mon); + _fstab_mon = NULL; + _watching = EINA_FALSE; +} + +EAPI Eina_Bool +eeze_mount_mtab_scan(void) +{ + libmnt_table *bak; + + if (_watching) + return EINA_TRUE; + + if (!_eeze_mount_lock_mtab()) + return EINA_FALSE; + bak = _eeze_mount_tab_parse("/etc/mtab"); + _eeze_mount_unlock_mtab(); + if (!bak) + goto error; + if (_eeze_mount_mtab) + { + mnt_free_table(_eeze_mount_mtab); + mnt_free_cache(_eeze_mount_mtab_cache); + } + _eeze_mount_mtab = bak; + _eeze_mount_mtab_cache = mnt_new_cache(); + mnt_table_set_cache(_eeze_mount_mtab, _eeze_mount_mtab_cache); + + return EINA_TRUE; + +error: + return EINA_FALSE; +} + +EAPI Eina_Bool +eeze_mount_fstab_scan(void) +{ + libmnt_table *bak; + if (_watching) + return EINA_TRUE; + + bak = _eeze_mount_tab_parse("/etc/fstab"); + if (!bak) + goto error; + if (_eeze_mount_fstab) + { + mnt_free_table(_eeze_mount_fstab); + mnt_free_cache(_eeze_mount_fstab_cache); + } + _eeze_mount_fstab = bak; + _eeze_mount_fstab_cache = mnt_new_cache(); + mnt_table_set_cache(_eeze_mount_fstab, _eeze_mount_fstab_cache); + + return EINA_TRUE; + +error: + return EINA_FALSE; +} diff --git a/src/lib/eeze_disk_libmount_new.c b/src/lib/eeze_disk_libmount_new.c new file mode 100644 index 0000000..5811518 --- /dev/null +++ b/src/lib/eeze_disk_libmount_new.c @@ -0,0 +1,525 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef USE_UNSTABLE_LIBMOUNT_API +# define USE_UNSTABLE_LIBMOUNT_API 1 +#endif + +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <Ecore.h> +#include <Eeze.h> +#include <Eeze_Disk.h> +#include <libmount.h> +#include "eeze_udev_private.h" +#include "eeze_disk_private.h" + +/* + * + * PRIVATE + * + */ + +static struct libmnt_optmap eeze_optmap[] = +{ + { "loop[=]", EEZE_DISK_MOUNTOPT_LOOP, 0 }, + { "utf8", EEZE_DISK_MOUNTOPT_UTF8, 0 }, + { "noexec", EEZE_DISK_MOUNTOPT_NOEXEC, 0 }, + { "nosuid", EEZE_DISK_MOUNTOPT_NOSUID, 0 }, + { "remount", EEZE_DISK_MOUNTOPT_REMOUNT, 0 }, + { "uid[=]", EEZE_DISK_MOUNTOPT_UID, 0 }, + { "nodev", EEZE_DISK_MOUNTOPT_NODEV, 0 }, + { NULL, 0, 0 } +}; +typedef struct libmnt_table libmnt_table; +typedef struct libmnt_fs libmnt_fs; +typedef struct libmnt_cache libmnt_cache; +static Ecore_File_Monitor *_fstab_mon = NULL; +static Eina_Bool _watching = EINA_FALSE; +static Eina_Bool _fstab_scan_active = EINA_FALSE; +static libmnt_cache *_eeze_mount_mtab_cache = NULL; +static libmnt_cache *_eeze_mount_fstab_cache = NULL; +static libmnt_table *_eeze_mount_mtab = NULL; +static libmnt_table *_eeze_mount_fstab = NULL; +extern Eina_List *_eeze_disks; + +static Ecore_Fd_Handler *_mountinfo_fdh = NULL; +static int _mountinfo = -1; + +static libmnt_table *_eeze_mount_tab_parse(const char *filename); +static void _eeze_mount_tab_watcher(void *data, Ecore_File_Monitor *mon __UNUSED__, Ecore_File_Event event __UNUSED__, const char *path); + +static int +_eeze_mount_tab_parse_errcb(libmnt_table *tab __UNUSED__, const char *filename, int line) +{ + ERR("%s:%d: could not parse line!", filename, line); /* most worthless error reporting ever. */ + return -1; +} + +/* + * I could use mnt_new_table_from_file() but this way gives much more detailed output + * on failure so why not + */ +static libmnt_table * +_eeze_mount_tab_parse(const char *filename) +{ + libmnt_table *tab; + + if (!(tab = mnt_new_table())) return NULL; + if (mnt_table_set_parser_errcb(tab, _eeze_mount_tab_parse_errcb)) + { + ERR("Alloc!"); + mnt_free_table(tab); + return NULL; + } + + if (!mnt_table_parse_file(tab, filename)) + return tab; + + mnt_free_table(tab); + return NULL; +} + +static void +_eeze_mount_tab_watcher(void *data, Ecore_File_Monitor *mon __UNUSED__, Ecore_File_Event event __UNUSED__, const char *path) +{ + libmnt_table *bak; + + if (_fstab_scan_active) + /* prevent scans from triggering a scan */ + return; + + bak = _eeze_mount_mtab; + _eeze_mount_mtab = _eeze_mount_tab_parse(path); + if (!_eeze_mount_mtab) + { + ERR("Could not parse %s! keeping old tab...", path); + goto error; + } + + mnt_free_table(bak); + if (data) + { + mnt_free_cache(_eeze_mount_mtab_cache); + _eeze_mount_mtab_cache = mnt_new_cache(); + mnt_table_set_cache(_eeze_mount_mtab, _eeze_mount_mtab_cache); + } + else + { + mnt_free_cache(_eeze_mount_fstab_cache); + _eeze_mount_fstab_cache = mnt_new_cache(); + mnt_table_set_cache(_eeze_mount_fstab, _eeze_mount_fstab_cache); + } + return; + +error: + mnt_free_table(_eeze_mount_mtab); + _eeze_mount_mtab = bak; +} + +/* on tab change, check differences + * based on code from findmnt + */ +static Eina_Bool +_eeze_mount_fdh(void *d __UNUSED__, Ecore_Fd_Handler *fdh __UNUSED__) +{ + libmnt_table *tb_new; + libmnt_fs *old, *new; + int change; + struct libmnt_iter *itr = NULL; + struct libmnt_tabdiff *diff = NULL; + + tb_new = mnt_new_table(); + EINA_SAFETY_ON_NULL_RETURN_VAL(tb_new, ECORE_CALLBACK_RENEW); + EINA_SAFETY_ON_TRUE_GOTO(mnt_table_set_parser_errcb(tb_new, _eeze_mount_tab_parse_errcb), err); + itr = mnt_new_iter(MNT_ITER_BACKWARD); + EINA_SAFETY_ON_NULL_GOTO(itr, err); + diff = mnt_new_tabdiff(); + EINA_SAFETY_ON_NULL_GOTO(diff, err); + if (mnt_table_parse_file(tb_new, "/proc/self/mountinfo")) + { + ERR("PARSING FAILED FOR /proc/self/mountinfo! THIS IS WEIRD!"); + goto err; + } + change = mnt_diff_tables(diff, _eeze_mount_mtab, tb_new); + if (change < 0) + { + ERR("DIFFING FAILED FOR /proc/self/mountinfo! THIS IS ALSO WEIRD!"); + goto err; + } + if (!change) goto err; + while (!mnt_tabdiff_next_change(diff, itr, &old, &new, &change)) + { + const char *src; + Eeze_Disk *disk; + Eina_Bool found = EINA_FALSE; + Eeze_Event_Disk_Mount *e; + Eina_List *l; + + src = mnt_fs_get_source(new); + if (!src) continue; + EINA_LIST_FOREACH(_eeze_disks, l, disk) + { + if (!strcmp(src, eeze_disk_devpath_get(disk))) + { + found = EINA_TRUE; + break; + } + } + if (!found) continue; + switch (change) + { + case MNT_TABDIFF_MOUNT: + disk->mounted = EINA_TRUE; + eina_stringshare_replace(&disk->mount_point, mnt_fs_get_target(new)); + if (disk->mount_status) break; + e = malloc(sizeof(Eeze_Event_Disk_Mount)); + if (e) + { + e->disk = disk; + ecore_event_add(EEZE_EVENT_DISK_MOUNT, e, NULL, NULL); + } + break; + case MNT_TABDIFF_UMOUNT: + if (!mnt_fs_get_target(new)) + disk->mounted = EINA_FALSE; + eina_stringshare_replace(&disk->mount_point, NULL); + if (disk->mount_status) break; + e = malloc(sizeof(Eeze_Event_Disk_Mount)); + if (e) + { + e->disk = disk; + ecore_event_add(EEZE_EVENT_DISK_UNMOUNT, e, NULL, NULL); + } + break; + /* anything could have happened here, send both events to flush */ + case MNT_TABDIFF_REMOUNT: + case MNT_TABDIFF_MOVE: + if (!mnt_fs_get_target(new)) + disk->mounted = EINA_FALSE; + eina_stringshare_replace(&disk->mount_point, mnt_fs_get_target(new)); + if (disk->mount_status) break; + e = malloc(sizeof(Eeze_Event_Disk_Mount)); + if (e) + { + e->disk = disk; + ecore_event_add(EEZE_EVENT_DISK_UNMOUNT, e, NULL, NULL); + } + e = malloc(sizeof(Eeze_Event_Disk_Mount)); + if (e) + { + e->disk = disk; + ecore_event_add(EEZE_EVENT_DISK_MOUNT, e, NULL, NULL); + } + default: + break; + } + } + + mnt_free_cache(_eeze_mount_mtab_cache); + _eeze_mount_mtab_cache = mnt_new_cache(); + mnt_table_set_cache(_eeze_mount_mtab, _eeze_mount_mtab_cache); + mnt_free_table(_eeze_mount_mtab); + _eeze_mount_mtab = tb_new; + return ECORE_CALLBACK_RENEW; +err: + if (tb_new) mnt_free_table(tb_new); + if (itr) mnt_free_iter(itr); + if (diff) mnt_free_tabdiff(diff); + return ECORE_CALLBACK_RENEW; +} + +/* + * + * INVISIBLE + * + */ + +Eina_Bool +eeze_libmount_init(void) +{ + /* placeholder */ + return EINA_TRUE; +} + +void +eeze_libmount_shutdown(void) +{ + if (_eeze_mount_fstab) + { + mnt_free_table(_eeze_mount_fstab); + mnt_free_cache(_eeze_mount_fstab_cache); + } + if (_eeze_mount_mtab) + { + mnt_free_table(_eeze_mount_mtab); + mnt_free_cache(_eeze_mount_mtab_cache); + } + eeze_mount_tabs_unwatch(); +} + +unsigned long +eeze_disk_libmount_opts_get(Eeze_Disk *disk) +{ + libmnt_fs *mnt; + const char *opts; + unsigned long f = 0; + + if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan()) + return 0; + + mnt = mnt_table_find_tag(_eeze_mount_mtab, "UUID", eeze_disk_uuid_get(disk), MNT_ITER_BACKWARD); + if (!mnt) + mnt = mnt_table_find_tag(_eeze_mount_fstab, "UUID", eeze_disk_uuid_get(disk), MNT_ITER_BACKWARD); + + if (!mnt) return 0; + + opts = mnt_fs_get_fs_options(mnt); + if (!opts) return 0; + if (!mnt_optstr_get_flags(opts, &f, eeze_optmap)) return 0; + return f; +} + +/* + * helper function to return whether a disk is mounted + */ +Eina_Bool +eeze_disk_libmount_mounted_get(Eeze_Disk *disk) +{ + libmnt_fs *mnt; + + if (!disk) + return EINA_FALSE; + + if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan()) + return EINA_FALSE; + + mnt = mnt_table_find_source(_eeze_mount_mtab, eeze_disk_devpath_get(disk), MNT_ITER_BACKWARD); + if (!mnt) + { + disk->mounted = EINA_FALSE; + return EINA_FALSE; + } + + eina_stringshare_replace(&disk->mount_point, mnt_fs_get_target(mnt)); + disk->mounted = EINA_TRUE; + return EINA_TRUE; +} + + +/* + * helper function to return the device that is mounted at a mount point + */ +const char * +eeze_disk_libmount_mp_find_source(const char *mount_point) +{ + libmnt_fs *mnt; + + if (!mount_point) + return NULL; + + if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan()) + return NULL; + + mnt = mnt_table_find_target(_eeze_mount_mtab, mount_point, MNT_ITER_BACKWARD); + if (!mnt) + mnt = mnt_table_find_target(_eeze_mount_fstab, mount_point, MNT_ITER_BACKWARD); + + if (!mnt) + return NULL; + + return mnt_fs_get_source(mnt); +} + +/* + * helper function to return a mount point from a uuid + */ +const char * +eeze_disk_libmount_mp_lookup_by_uuid(const char *uuid) +{ + libmnt_fs *mnt; + + if (!uuid) + return NULL; + + if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan()) + return NULL; + + mnt = mnt_table_find_tag(_eeze_mount_fstab, "UUID", uuid, MNT_ITER_BACKWARD); + + if (!mnt) + return NULL; + + return mnt_fs_get_target(mnt); +} + +/* + * helper function to return a mount point from a label + */ +const char * +eeze_disk_libmount_mp_lookup_by_label(const char *label) +{ + libmnt_fs *mnt; + + if (!label) + return NULL; + + if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan()) + return NULL; + + mnt = mnt_table_find_tag(_eeze_mount_fstab, "LABEL", label, MNT_ITER_BACKWARD); + + if (!mnt) + return NULL; + + return mnt_fs_get_target(mnt); +} + +/* + * helper function to return a mount point from a /dev/ path + */ +const char * +eeze_disk_libmount_mp_lookup_by_devpath(const char *devpath) +{ + libmnt_fs *mnt; + + if (!devpath) + return NULL; + + if (!eeze_mount_mtab_scan() || !eeze_mount_fstab_scan()) + return NULL; + + mnt = mnt_table_find_srcpath(_eeze_mount_mtab, devpath, MNT_ITER_BACKWARD); + if (!mnt) + mnt = mnt_table_find_srcpath(_eeze_mount_fstab, devpath, MNT_ITER_BACKWARD); + + if (!mnt) + return NULL; + + return mnt_fs_get_target(mnt); +} + +/* + * + * API + * + */ + +EAPI Eina_Bool +eeze_mount_tabs_watch(void) +{ + libmnt_table *bak; + + if (_watching) + return EINA_TRUE; + + bak = _eeze_mount_tab_parse("/proc/self/mountinfo"); + EINA_SAFETY_ON_NULL_GOTO(bak, error); + + mnt_free_table(_eeze_mount_mtab); + _eeze_mount_mtab = bak; + bak = _eeze_mount_tab_parse("/etc/fstab"); + EINA_SAFETY_ON_NULL_GOTO(bak, error); + + mnt_free_table(_eeze_mount_fstab); + _eeze_mount_fstab = bak; + + _eeze_mount_mtab_cache = mnt_new_cache(); + mnt_table_set_cache(_eeze_mount_mtab, _eeze_mount_mtab_cache); + + _eeze_mount_fstab_cache = mnt_new_cache(); + mnt_table_set_cache(_eeze_mount_fstab, _eeze_mount_fstab_cache); + + _mountinfo = open("/proc/self/mountinfo", O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + if (_mountinfo < 0) goto error; + if (fcntl(_mountinfo, F_SETFL, O_NONBLOCK) < 0) goto error; + + _mountinfo_fdh = ecore_main_fd_handler_file_add(_mountinfo, ECORE_FD_ERROR, _eeze_mount_fdh, NULL, NULL, NULL); + if (!_mountinfo_fdh) goto error; + _fstab_mon = ecore_file_monitor_add("/etc/fstab", _eeze_mount_tab_watcher, NULL); + _watching = EINA_TRUE; + + return EINA_TRUE; + +error: + if (_mountinfo >= 0) close(_mountinfo); + _mountinfo = -1; + if (!_eeze_mount_mtab) + ERR("Could not parse /proc/self/mountinfo!"); + else + { + ERR("Could not parse /etc/fstab!"); + mnt_free_table(_eeze_mount_mtab); + } + _eeze_mount_mtab = _eeze_mount_fstab = NULL; + return EINA_FALSE; +} + +EAPI void +eeze_mount_tabs_unwatch(void) +{ + if (!_watching) + return; + + ecore_main_fd_handler_del(_mountinfo_fdh); + ecore_file_monitor_del(_fstab_mon); + close(_mountinfo); + _mountinfo = -1; + _fstab_mon = NULL; + _watching = EINA_FALSE; +} + +EAPI Eina_Bool +eeze_mount_mtab_scan(void) +{ + libmnt_table *bak; + + if (_watching) + return EINA_TRUE; + + bak = _eeze_mount_tab_parse("/proc/self/mountinfo"); + if (!bak) + goto error; + if (_eeze_mount_mtab) + { + mnt_free_table(_eeze_mount_mtab); + mnt_free_cache(_eeze_mount_mtab_cache); + } + _eeze_mount_mtab = bak; + _eeze_mount_mtab_cache = mnt_new_cache(); + mnt_table_set_cache(_eeze_mount_mtab, _eeze_mount_mtab_cache); + + return EINA_TRUE; + +error: + return EINA_FALSE; +} + +EAPI Eina_Bool +eeze_mount_fstab_scan(void) +{ + libmnt_table *bak; + if (_watching) + return EINA_TRUE; + + bak = _eeze_mount_tab_parse("/etc/fstab"); + if (!bak) + goto error; + if (_eeze_mount_fstab) + { + mnt_free_table(_eeze_mount_fstab); + mnt_free_cache(_eeze_mount_fstab_cache); + } + _eeze_mount_fstab = bak; + _eeze_mount_fstab_cache = mnt_new_cache(); + mnt_table_set_cache(_eeze_mount_fstab, _eeze_mount_fstab_cache); + + return EINA_TRUE; + +error: + return EINA_FALSE; +} diff --git a/src/lib/eeze_disk_libmount_old.c b/src/lib/eeze_disk_libmount_old.c new file mode 100644 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..24c0ae4 --- /dev/null +++ b/src/lib/eeze_disk_mount.c @@ -0,0 +1,465 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <errno.h> + +#include <Ecore.h> +#include <Eeze.h> +#include <Eeze_Disk.h> + +#include "eeze_udev_private.h" +#include "eeze_disk_private.h" + +#define EEZE_MOUNT_DEFAULT_OPTS "noexec,nosuid,utf8" + +EAPI int EEZE_EVENT_DISK_MOUNT = 0; +EAPI int EEZE_EVENT_DISK_UNMOUNT = 0; +EAPI int EEZE_EVENT_DISK_EJECT = 0; +EAPI int EEZE_EVENT_DISK_ERROR = 0; +static Ecore_Event_Handler *_mount_handler = NULL; +Eina_List *eeze_events = NULL; + +/* + * + * PRIVATE + * + */ + +static void +_eeze_disk_mount_error_free(void *data __UNUSED__, Eeze_Event_Disk_Error *de) +{ + if (!de) + return; + + eina_stringshare_del(de->message); + free(de); +} + +static void +_eeze_disk_mount_error_handler(Eeze_Disk *disk, const char *error) +{ + Eeze_Event_Disk_Error *de; + + ERR("%s", error); + if (!(de = calloc(1, sizeof(Eeze_Event_Disk_Error)))) + return; + + de->disk = disk; + de->message = eina_stringshare_add(error); + /* FIXME: placeholder since currently there are only mount-type errors */ + ecore_event_add(EEZE_EVENT_DISK_ERROR, de, (Ecore_End_Cb)_eeze_disk_mount_error_free, NULL); +} + +static Eina_Bool +_eeze_disk_mount_result_handler(void *data __UNUSED__, int type __UNUSED__, Ecore_Exe_Event_Del *ev) +{ + Eeze_Disk *disk; + Eina_List *l; + Eeze_Event_Disk_Mount *e; + + if ((!ev) || (!ev->exe)) + return ECORE_CALLBACK_RENEW; + disk = ecore_exe_data_get(ev->exe); + + if ((!disk) || (!eeze_events) || (!(l = eina_list_data_find_list(eeze_events, disk)))) + return ECORE_CALLBACK_RENEW; + + eeze_events = eina_list_remove_list(eeze_events, l); + if (!disk->mounter) /* killed */ + { + disk->mount_status = EEZE_DISK_NULL; + return ECORE_CALLBACK_RENEW; + } + if (disk->mount_status == EEZE_DISK_MOUNTING) + { + disk->mounter = NULL; + if (!ev->exit_code) + { + disk->mounted = EINA_TRUE; + e = malloc(sizeof(Eeze_Event_Disk_Mount)); + EINA_SAFETY_ON_NULL_RETURN_VAL(e, ECORE_CALLBACK_RENEW); + e->disk = disk; + ecore_event_add(EEZE_EVENT_DISK_MOUNT, e, NULL, NULL); + } + else if (ev->exit_code & 2) + _eeze_disk_mount_error_handler(disk, "system error (out of memory, cannot fork, no more loop devices)"); + else if (ev->exit_code & 4) + _eeze_disk_mount_error_handler(disk, "internal mount bug"); + else if (ev->exit_code & 8) + _eeze_disk_mount_error_handler(disk, "user interrupt"); + else if (ev->exit_code & 16) + _eeze_disk_mount_error_handler(disk, "problems writing or locking /etc/mtab"); + else if (ev->exit_code & 32) + _eeze_disk_mount_error_handler(disk, "mount failure"); + else if (ev->exit_code & 64) + _eeze_disk_mount_error_handler(disk, "some mount succeeded"); + else + _eeze_disk_mount_error_handler(disk, "incorrect invocation or permissions"); + } + else if (disk->mount_status == EEZE_DISK_UNMOUNTING) + switch (ev->exit_code) + { + case 0: + e = malloc(sizeof(Eeze_Event_Disk_Unmount)); + EINA_SAFETY_ON_NULL_RETURN_VAL(e, ECORE_CALLBACK_RENEW); + e->disk = disk; + disk->mounter = NULL; + disk->mounted = EINA_FALSE; + ecore_event_add(EEZE_EVENT_DISK_UNMOUNT, e, NULL, NULL); + break; + + default: + if (disk->mount_fail_count++ < 3) + { + INF("Could not unmount disk, retrying"); + disk->mounter = ecore_exe_run(eina_strbuf_string_get(disk->unmount_cmd), disk); + eeze_events = eina_list_append(eeze_events, disk); + } + else + { + disk->mount_fail_count = 0; + _eeze_disk_mount_error_handler(disk, "Maximimum number of mount-related failures reached"); + } + return ECORE_CALLBACK_RENEW; + } + else + switch (ev->exit_code) + { + case 0: + e = malloc(sizeof(Eeze_Event_Disk_Eject)); + EINA_SAFETY_ON_NULL_RETURN_VAL(e, ECORE_CALLBACK_RENEW); + e->disk = disk; + disk->mounter = NULL; + if (disk->mount_status & EEZE_DISK_UNMOUNTING) + { + disk->mount_status |= EEZE_DISK_UNMOUNTING; + disk->mounted = EINA_FALSE; + ecore_event_add(EEZE_EVENT_DISK_UNMOUNT, e, NULL, NULL); + eeze_disk_eject(disk); + } + else + ecore_event_add(EEZE_EVENT_DISK_EJECT, e, NULL, NULL); + break; + + default: + if (disk->mount_fail_count++ < 3) + { + INF("Could not eject disk, retrying"); + if (disk->mount_status & EEZE_DISK_UNMOUNTING) + disk->mounter = ecore_exe_run(eina_strbuf_string_get(disk->unmount_cmd), disk); + else + disk->mounter = ecore_exe_run(eina_strbuf_string_get(disk->eject_cmd), disk); + eeze_events = eina_list_append(eeze_events, disk); + } + else + { + disk->mount_fail_count = 0; + _eeze_disk_mount_error_handler(disk, "Maximimum number of mount-related failures reached"); + } + return ECORE_CALLBACK_RENEW; + } + return ECORE_CALLBACK_RENEW; +} + +/* + * + * INVISIBLE + * + */ + +Eina_Bool +eeze_mount_init(void) +{ + EEZE_EVENT_DISK_MOUNT = ecore_event_type_new(); + EEZE_EVENT_DISK_UNMOUNT = ecore_event_type_new(); + EEZE_EVENT_DISK_EJECT = ecore_event_type_new(); + EEZE_EVENT_DISK_ERROR = ecore_event_type_new(); + _mount_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, + (Ecore_Event_Handler_Cb)_eeze_disk_mount_result_handler, NULL); + return eeze_libmount_init(); +} + +void +eeze_mount_shutdown(void) +{ + eeze_libmount_shutdown(); + ecore_event_handler_del(_mount_handler); + _mount_handler = NULL; +} + +/* + * + * API + * + */ + +EAPI Eina_Bool +eeze_disk_mounted_get(Eeze_Disk *disk) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE); + + return eeze_disk_libmount_mounted_get(disk); +} + +EAPI Eina_Bool +eeze_disk_mountopts_set(Eeze_Disk *disk, unsigned long opts) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE); + if (opts != disk->mount_opts) + disk->mount_cmd_changed = EINA_TRUE; + disk->mount_opts = opts; + if (opts & EEZE_DISK_MOUNTOPT_UID) + disk->uid = getuid(); + return EINA_TRUE; +} + +EAPI unsigned long +eeze_disk_mountopts_get(Eeze_Disk *disk) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(disk, 0); +#ifndef OLD_LIBMOUNT + if (!disk->mount_opts) + disk->mount_opts = eeze_disk_libmount_opts_get(disk); +#endif + return disk->mount_opts; +} + +EAPI Eina_Bool +eeze_disk_mount_wrapper_set(Eeze_Disk *disk, const char *wrapper) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE); + if (wrapper) EINA_SAFETY_ON_TRUE_RETURN_VAL(!*wrapper, EINA_FALSE); + else + { + eina_stringshare_del(disk->mount_wrapper); + disk->mount_wrapper = NULL; + return EINA_TRUE; + } + eina_stringshare_replace(&disk->mount_wrapper, wrapper); + return EINA_TRUE; +} + +EAPI const char * +eeze_disk_mount_wrapper_get(Eeze_Disk *disk) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL); + return disk->mount_wrapper; +} + +EAPI Eina_Bool +eeze_disk_mount(Eeze_Disk *disk) +{ + struct stat st; + EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE); + + if ((!disk->mount_point) && eeze_disk_libmount_mounted_get(disk)) + return EINA_FALSE; + + if (!disk->mount_cmd) + disk->mount_cmd = eina_strbuf_new(); + + if (disk->mount_cmd_changed) + { + const char *dev, *str; + eina_strbuf_string_free(disk->mount_cmd); + dev = eeze_disk_uuid_get(disk); + if (dev) str = "UUID="; + else + { + dev = eeze_disk_devpath_get(disk); + str = NULL; + } + + if (!disk->mount_point) + { + const char *mp; + /* here we attempt to guess the mount point using libmount */ + mp = eeze_disk_libmount_mp_lookup_by_uuid(disk->cache.uuid); + if (!mp) + { + const char *devpath; + + devpath = eeze_disk_devpath_get(disk); + if (devpath) + { + mp = eeze_disk_libmount_mp_lookup_by_devpath(devpath); + eina_stringshare_del(devpath); + } + } + if (!eeze_disk_mount_point_set(disk, mp)) + /* sometimes we fail */ + return EINA_FALSE; + } + + if ((!disk->mount_point) || (!disk->mount_point[0])) return EINA_FALSE; + if (disk->mount_wrapper) + eina_strbuf_append_printf(disk->mount_cmd, "%s ", disk->mount_wrapper); + if (disk->mount_opts == EEZE_DISK_MOUNTOPT_DEFAULTS) + eina_strbuf_append_printf(disk->mount_cmd, EEZE_MOUNT_BIN" -o "EEZE_MOUNT_DEFAULT_OPTS" %s%s %s", str ?: "", dev, disk->mount_point); + else if (!disk->mount_opts) + eina_strbuf_append_printf(disk->mount_cmd, EEZE_MOUNT_BIN" %s%s %s", str ?: "", dev, disk->mount_point); + else + { + eina_strbuf_append(disk->mount_cmd, EEZE_MOUNT_BIN" -o "); + /* trailing commas are okay */ + if (disk->mount_opts & EEZE_DISK_MOUNTOPT_LOOP) + eina_strbuf_append(disk->mount_cmd, "loop,"); + if (disk->mount_opts & EEZE_DISK_MOUNTOPT_UTF8) + { + const char *fstype; + eina_strbuf_append(disk->mount_cmd, "utf8,"); + fstype = eeze_disk_fstype_get(disk); + if (fstype && (!strcmp(fstype, "jfs"))) + eina_strbuf_append(disk->mount_cmd, "iocharset=utf8,"); + } + if (disk->mount_opts & EEZE_DISK_MOUNTOPT_NOEXEC) + eina_strbuf_append(disk->mount_cmd, "noexec,"); + if (disk->mount_opts & EEZE_DISK_MOUNTOPT_NODEV) + eina_strbuf_append(disk->mount_cmd, "nodev,"); + if (disk->mount_opts & EEZE_DISK_MOUNTOPT_NOSUID) + eina_strbuf_append(disk->mount_cmd, "nosuid,"); + if (disk->mount_opts & EEZE_DISK_MOUNTOPT_REMOUNT) + eina_strbuf_append(disk->mount_cmd, "remount,"); + if (disk->mount_opts & EEZE_DISK_MOUNTOPT_UID) + eina_strbuf_append_printf(disk->mount_cmd, "uid=%i,", (int)disk->uid); + eina_strbuf_append_printf(disk->mount_cmd, " %s%s %s", str ?: "", dev, disk->mount_point); + } + disk->mount_cmd_changed = EINA_FALSE; + } + + if (stat(disk->mount_point, &st)) + { + INF("Creating not-existing mount point directory '%s'", disk->mount_point); + if (mkdir(disk->mount_point, S_IROTH | S_IWOTH | S_IXOTH)) + ERR("Could not create directory: %s; hopefully this is handled by your mounter!", strerror(errno)); + } + else if (!S_ISDIR(st.st_mode)) + { + ERR("%s is not a directory!", disk->mount_point); + return EINA_FALSE; + } + INF("Mounting: %s", eina_strbuf_string_get(disk->mount_cmd)); + disk->mounter = ecore_exe_run(eina_strbuf_string_get(disk->mount_cmd), disk); + if (!disk->mounter) + return EINA_FALSE; + eeze_events = eina_list_append(eeze_events, disk); + disk->mount_status = EEZE_DISK_MOUNTING; + + return EINA_TRUE; +} + +EAPI Eina_Bool +eeze_disk_unmount(Eeze_Disk *disk) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE); + + if (!eeze_disk_libmount_mounted_get(disk)) + return EINA_TRUE; + + if (!disk->unmount_cmd) + disk->unmount_cmd = eina_strbuf_new(); + + if (disk->unmount_cmd_changed) + { + eina_strbuf_string_free(disk->unmount_cmd); + if (disk->mount_wrapper) + eina_strbuf_append_printf(disk->unmount_cmd, "%s ", disk->mount_wrapper); + eina_strbuf_append_printf(disk->unmount_cmd, EEZE_UNMOUNT_BIN" %s", eeze_disk_devpath_get(disk)); + disk->unmount_cmd_changed = EINA_FALSE; + } + + INF("Unmounting: %s", eina_strbuf_string_get(disk->unmount_cmd)); + disk->mounter = ecore_exe_run(eina_strbuf_string_get(disk->unmount_cmd), disk); + if (!disk->mounter) + return EINA_FALSE; + + eeze_events = eina_list_append(eeze_events, disk); + disk->mount_status = EEZE_DISK_UNMOUNTING; + return EINA_TRUE; +} + +EAPI Eina_Bool +eeze_disk_eject(Eeze_Disk *disk) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE); + + if (!disk->eject_cmd) + { + disk->eject_cmd = eina_strbuf_new(); + if (disk->mount_wrapper) + eina_strbuf_append_printf(disk->eject_cmd, "%s ", disk->mount_wrapper); + eina_strbuf_append_printf(disk->eject_cmd, EEZE_EJECT_BIN" %s", eeze_disk_devpath_get(disk)); + } + + INF("Ejecting: %s", eina_strbuf_string_get(disk->eject_cmd)); + if (eeze_disk_libmount_mounted_get(disk)) + { + Eina_Bool ret; + + ret = eeze_disk_unmount(disk); + if (ret) disk->mount_status |= EEZE_DISK_EJECTING; + return ret; + } + disk->mounter = ecore_exe_run(eina_strbuf_string_get(disk->eject_cmd), disk); + if (!disk->mounter) + return EINA_FALSE; + + eeze_events = eina_list_append(eeze_events, disk); + disk->mount_status = EEZE_DISK_EJECTING; + return EINA_TRUE; +} + +EAPI void +eeze_disk_cancel(Eeze_Disk *disk) +{ + EINA_SAFETY_ON_NULL_RETURN(disk); + if ((!disk->mount_status) || (!disk->mounter)) return; + disk->mount_status = EEZE_DISK_NULL; + ecore_exe_kill(disk->mounter); + disk->mounter = NULL; +} + +EAPI const char * +eeze_disk_mount_point_get(Eeze_Disk *disk) +{ + const char *mp; + EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL); + + if (disk->mount_point) + return disk->mount_point; + + mp = eeze_disk_libmount_mp_lookup_by_devpath(eeze_disk_devpath_get(disk)); + if (mp) + { + disk->mount_point = eina_stringshare_add(mp); + return disk->mount_point; + } + mp = eeze_disk_libmount_mp_lookup_by_uuid(eeze_disk_uuid_get(disk)); + if (mp) + { + disk->mount_point = eina_stringshare_add(mp); + return disk->mount_point; + } + mp = eeze_disk_libmount_mp_lookup_by_label(eeze_disk_label_get(disk)); + if (mp) + { + disk->mount_point = eina_stringshare_add(mp); + return disk->mount_point; + } + return NULL; +} + +EAPI Eina_Bool +eeze_disk_mount_point_set(Eeze_Disk *disk, const char *mount_point) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE); + + eina_stringshare_replace(&disk->mount_point, mount_point); + disk->mount_cmd_changed = EINA_TRUE; + disk->unmount_cmd_changed = EINA_TRUE; + return EINA_TRUE; +} diff --git a/src/lib/eeze_disk_private.h b/src/lib/eeze_disk_private.h new file mode 100644 index 0000000..0174b9e --- /dev/null +++ b/src/lib/eeze_disk_private.h @@ -0,0 +1,93 @@ +#ifndef EEZE_DISK_PRIVATE_H +#define EEZE_DISK_PRIVATE_H +#include <Eeze.h> +#include <Ecore_File.h> + +#ifndef EEZE_DISK_COLOR_DEFAULT +#define EEZE_DISK_COLOR_DEFAULT EINA_COLOR_LIGHTBLUE +#endif +extern int _eeze_disk_log_dom; +#ifdef CRI +#undef CRI +#endif + +#ifdef ERR +#undef ERR +#endif +#ifdef INF +#undef INF +#endif +#ifdef WARN +#undef WARN +#endif +#ifdef DBG +#undef DBG +#endif + +#define CRI(...) EINA_LOG_DOM_CRIT(_eeze_disk_log_dom, __VA_ARGS__) +#define DBG(...) EINA_LOG_DOM_DBG(_eeze_disk_log_dom, __VA_ARGS__) +#define INF(...) EINA_LOG_DOM_INFO(_eeze_disk_log_dom, __VA_ARGS__) +#define WARN(...) EINA_LOG_DOM_WARN(_eeze_disk_log_dom, __VA_ARGS__) +#define ERR(...) EINA_LOG_DOM_ERR(_eeze_disk_log_dom, __VA_ARGS__) + +typedef enum +{ + EEZE_DISK_NULL = 0, + EEZE_DISK_MOUNTING = 1, + EEZE_DISK_UNMOUNTING = 2, + EEZE_DISK_EJECTING = 4 +} Eeze_Disk_Status; + +struct _Eeze_Disk +{ + _udev_device *device; + void *data; + + int mount_status; + Eina_Strbuf *mount_cmd; + Eina_Strbuf *unmount_cmd; + Eina_Strbuf *eject_cmd; + Eina_Bool mount_cmd_changed : 1; + Eina_Bool unmount_cmd_changed : 1; + Eina_Bool mounted : 1; + Ecore_Exe *mounter; + unsigned int mount_fail_count; + + const char *syspath; + const char *devpath; + const char *fstype; + const char *mount_point; + const char *mount_wrapper; + unsigned long mount_opts; + uid_t uid; + + struct + { + Eeze_Disk_Type type; + Eina_Bool removable : 1; + const char *vendor; + const char *model; + const char *serial; + const char *uuid; + const char *label; + Eina_Bool filled : 1; + } cache; +}; + +Eina_Bool eeze_disk_init(void); +void eeze_disk_shutdown(void); + +Eina_Bool eeze_mount_init(void); +void eeze_mount_shutdown(void); + +Eina_Bool eeze_libmount_init(void); +void eeze_libmount_shutdown(void); +Eina_Bool eeze_disk_libmount_mounted_get(Eeze_Disk *disk); +unsigned long eeze_disk_libmount_opts_get(Eeze_Disk *disk); +const char *eeze_disk_libmount_mp_find_source(const char *mount_point); + +const char *eeze_disk_libmount_mp_lookup_by_uuid(const char *uuid); +const char *eeze_disk_libmount_mp_lookup_by_label(const char *label); +const char *eeze_disk_libmount_mp_lookup_by_devpath(const char *devpath); + +#endif diff --git a/src/lib/eeze_disk_udev.c b/src/lib/eeze_disk_udev.c new file mode 100644 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..0083b81 --- /dev/null +++ b/src/lib/eeze_udev_watch.c @@ -0,0 +1,449 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include <Ecore.h> +#include <Eeze.h> +#include "eeze_udev_private.h" + +/* opaque */ +struct Eeze_Udev_Watch +{ + _udev_monitor *mon; + Ecore_Fd_Handler *handler; + Eeze_Udev_Type type; + void *data; +}; + +/* private */ +struct _store_data +{ + void (*func)(const char *, + Eeze_Udev_Event, + void *, + Eeze_Udev_Watch *); + void *data; + Eeze_Udev_Event event; + _udev_monitor *mon; + Eeze_Udev_Type type; + Eeze_Udev_Watch *watch; +}; + +/* private function to further filter watch results based on Eeze_Udev_Type + * specified; helpful for new udev versions, but absolutely required for + * old udev, which does not implement filtering in device monitors. + */ +static Eina_Bool +_get_syspath_from_watch(void *data, + Ecore_Fd_Handler *fd_handler) +{ + struct _store_data *store = data; + _udev_device *device = NULL, *parent, *tmpdev; + const char *ret, *test; + Eeze_Udev_Watch_Cb func = store->func; + void *sdata = store->data; + Eeze_Udev_Watch *watch = store->watch; + int event = 0; + + if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) + return EINA_TRUE; + + device = udev_monitor_receive_device(store->mon); + + if (!device) + return EINA_TRUE; + + if ((!(test = udev_device_get_action(device))) + || (!(ret = udev_device_get_syspath(device)))) + goto error; + + if (store->event) + { + if (!strcmp(test, "add")) + { + if ((store->event != EEZE_UDEV_EVENT_NONE) && + ((store->event & EEZE_UDEV_EVENT_ADD) != EEZE_UDEV_EVENT_ADD)) + goto error; + + event |= EEZE_UDEV_EVENT_ADD; + } + else if (!strcmp(test, "remove")) + { + if ((store->event != EEZE_UDEV_EVENT_NONE) && + ((store->event & EEZE_UDEV_EVENT_REMOVE) != EEZE_UDEV_EVENT_REMOVE)) + goto error; + + event |= EEZE_UDEV_EVENT_REMOVE; + } + else if (!strcmp(test, "change")) + { + if ((store->event != EEZE_UDEV_EVENT_NONE) && + ((store->event & EEZE_UDEV_EVENT_CHANGE) != EEZE_UDEV_EVENT_CHANGE)) + goto error; + + event |= EEZE_UDEV_EVENT_CHANGE; + } + else if (!strcmp(test, "online")) + { + if ((store->event != EEZE_UDEV_EVENT_NONE) && + ((store->event & EEZE_UDEV_EVENT_ONLINE) != EEZE_UDEV_EVENT_ONLINE)) + goto error; + + event |= EEZE_UDEV_EVENT_ONLINE; + } + else + { + if ((store->event != EEZE_UDEV_EVENT_NONE) && + ((store->event & EEZE_UDEV_EVENT_OFFLINE) != EEZE_UDEV_EVENT_OFFLINE)) + goto error; + + event |= EEZE_UDEV_EVENT_OFFLINE; + } + } + + if ((event & EEZE_UDEV_EVENT_OFFLINE) || (event & EEZE_UDEV_EVENT_REMOVE)) + goto out; + switch (store->type) + { + case EEZE_UDEV_TYPE_KEYBOARD: +#ifdef OLD_UDEV_RRRRRRRRRRRRRR + if ((!(test = udev_device_get_subsystem(device))) + || (strcmp(test, "input"))) + goto error; + + test = udev_device_get_property_value(device, "ID_CLASS"); + + if ((_walk_parents_test_attr(device, "bInterfaceProtocol", "01")) + || ((test) && (!strcmp(test, "kbd")))) + break; + + goto error; +#endif + if ((!udev_device_get_property_value(device, "ID_INPUT_KEYBOARD")) && + (!udev_device_get_property_value(device, "ID_INPUT_KEY"))) + goto error; + + break; + + case EEZE_UDEV_TYPE_MOUSE: +#ifdef OLD_UDEV_RRRRRRRRRRRRRR + if ((!(test = udev_device_get_subsystem(device))) + || (strcmp(test, "input"))) + goto error; + + test = udev_device_get_property_value(device, "ID_CLASS"); + + if ((_walk_parents_test_attr(device, "bInterfaceProtocol", "02")) + || ((test) && (!strcmp(test, "mouse")))) + break; + + goto error; +#endif + + if (!udev_device_get_property_value(device, "ID_INPUT_MOUSE")) + goto error; + + break; + + case EEZE_UDEV_TYPE_TOUCHPAD: +#ifdef OLD_UDEV_RRRRRRRRRRRRRR + if ((!(test = udev_device_get_subsystem(device))) + || (strcmp(test, "input"))) + goto error; + + if (_walk_parents_test_attr(device, "resolution", NULL)) + break; + + goto error; +#endif + if (!udev_device_get_property_value(device, "ID_INPUT_TOUCHPAD")) + goto error; + + break; + + case EEZE_UDEV_TYPE_JOYSTICK: +#ifdef OLD_UDEV_RRRRRRRRRRRRRR + if ((!(test = udev_device_get_subsystem(device))) + || (strcmp(test, "input"))) + goto error; + + test = udev_device_get_property_value(device, "ID_CLASS"); + + if ((test) && (!strcmp(test, "joystick"))) + break; + + goto error; +#endif + if (!udev_device_get_property_value(device, "ID_INPUT_JOYSTICK")) + goto error; + + break; + + case EEZE_UDEV_TYPE_DRIVE_MOUNTABLE: +#ifdef OLD_UDEV_RRRRRRRRRRRRRR + if ((!(test = udev_device_get_subsystem(device))) + || (strcmp(test, "block"))) + goto error; +#endif + if (!(test = (udev_device_get_property_value(device, "ID_FS_USAGE"))) || + (strcmp("filesystem", test))) + { + if (event & EEZE_UDEV_EVENT_CHANGE) + { + test = udev_device_get_sysname(device); + if (!test) goto error; + if (!strncmp(test, "loop", 4)) break; + } + goto error; + } + { + int devcheck; + + devcheck = open(udev_device_get_devnode(device), O_RDONLY); + if (devcheck < 0) goto error; + close(devcheck); + } + + break; + + case EEZE_UDEV_TYPE_DRIVE_INTERNAL: + if (udev_device_get_property_value(device, "ID_FS_USAGE")) goto error; + test = udev_device_get_sysattr_value(device, "removable"); + if (test && test[0] == '1') goto error; + test = udev_device_get_property_value(device, "ID_BUS"); + if ((!test) || strcmp(test, "ata")) goto error; + test = udev_device_get_property_value(device, "ID_TYPE"); + if (!(event & EEZE_UDEV_EVENT_CHANGE) && ((!test) || strcmp(test, "disk"))) goto error; + break; + + case EEZE_UDEV_TYPE_DRIVE_REMOVABLE: + if (udev_device_get_sysattr_value(device, "partition")) goto error; + test = udev_device_get_sysattr_value(device, "removable"); + if ((!test) || (test[0] == '0')) goto error; + test = udev_device_get_property_value(device, "ID_TYPE"); + if ((!test) || strcmp(test, "disk")) goto error; + + break; + + case EEZE_UDEV_TYPE_DRIVE_CDROM: + if (!udev_device_get_property_value(device, "ID_CDROM")) + goto error; + + break; + + case EEZE_UDEV_TYPE_POWER_AC: +#ifdef OLD_UDEV_RRRRRRRRRRRRRR + if ((!(test = udev_device_get_subsystem(device))) + || (strcmp(test, "power_supply"))) + goto error; +#endif + test = udev_device_get_property_value(device, "POWER_SUPPLY_ONLINE"); + if (!test) goto error; + break; + + case EEZE_UDEV_TYPE_POWER_BAT: +#ifdef OLD_UDEV_RRRRRRRRRRRRRR + if ((!(test = udev_device_get_subsystem(device))) + || (strcmp(test, "power_supply"))) + goto error; +#endif + test = udev_device_get_property_value(device, "POWER_SUPPLY_PRESENT"); + if ((!test) || (strcmp(test, "1"))) goto error; + break; + + case EEZE_UDEV_TYPE_NET: +#ifdef OLD_UDEV_RRRRRRRRRRRRRR + if ((!(test = udev_device_get_subsystem(device))) + || (strcmp(test, "net"))) + goto error; +#endif + break; + + case EEZE_UDEV_TYPE_IS_IT_HOT_OR_IS_IT_COLD_SENSOR: + { + Eina_Bool one, two; + const char *t; + +#ifdef OLD_UDEV_RRRRRRRRRRRRRR + if ((!(test = udev_device_get_subsystem(device))) + || (strcmp(test, "hwmon"))) + goto error; +#endif /* have to do stuff up here since we need info from the parent */ + one = _walk_parents_test_attr(device, "temp1_input", NULL); + two = _walk_parents_test_attr(device, "temp2_input", NULL); + if ((!one) && (!two)) goto error; + + t = one ? "temp1_input" : "temp2_input"; + /* if device is not the one which has the temp input, we must go up the chain */ + if (!udev_device_get_sysattr_value(device, t)) + { + for (parent = udev_device_get_parent(device); parent; parent = udev_device_get_parent(parent)) /*check for parent */ + if (udev_device_get_sysattr_value(parent, t)) + { + tmpdev = device; + + if (!(device = _copy_device(parent))) + goto error; + + udev_device_unref(tmpdev); + break; + } + } + + break; + } + case EEZE_UDEV_TYPE_V4L: + if ((!(test = udev_device_get_subsystem(device))) + || (strcmp(test, "video4linux"))) + goto error; + break; + + case EEZE_UDEV_TYPE_BLUETOOTH: + if ((!(test = udev_device_get_subsystem(device))) + || (strcmp(test, "bluetooth"))) + goto error; + break; + + default: + break; + } +out: + (*func)(eina_stringshare_add(ret), event, sdata, watch); +error: + if (device) + udev_device_unref(device); + return EINA_TRUE; +} + +EAPI Eeze_Udev_Watch * +eeze_udev_watch_add(Eeze_Udev_Type type, + int event, + Eeze_Udev_Watch_Cb cb, + void *user_data) +{ + _udev_monitor *mon = NULL; + int fd; + Ecore_Fd_Handler *handler; + Eeze_Udev_Watch *watch = NULL; + struct _store_data *store = NULL; + + if (!(store = calloc(1, sizeof(struct _store_data)))) + return NULL; + + if (!(watch = malloc(sizeof(Eeze_Udev_Watch)))) + goto error; + + if (!(mon = udev_monitor_new_from_netlink(udev, "udev"))) + goto error; + +#ifndef OLD_UDEV_RRRRRRRRRRRRRR + + switch (type) + { + case EEZE_UDEV_TYPE_JOYSTICK: + case EEZE_UDEV_TYPE_KEYBOARD: + case EEZE_UDEV_TYPE_MOUSE: + case EEZE_UDEV_TYPE_TOUCHPAD: + udev_monitor_filter_add_match_subsystem_devtype(mon, "input", NULL); + break; + + case EEZE_UDEV_TYPE_DRIVE_MOUNTABLE: + case EEZE_UDEV_TYPE_DRIVE_INTERNAL: + udev_monitor_filter_add_match_subsystem_devtype(mon, "block", NULL); + break; + + case EEZE_UDEV_TYPE_DRIVE_REMOVABLE: + case EEZE_UDEV_TYPE_DRIVE_CDROM: + break; + + case EEZE_UDEV_TYPE_POWER_AC: + case EEZE_UDEV_TYPE_POWER_BAT: + udev_monitor_filter_add_match_subsystem_devtype(mon, "power_supply", + NULL); + break; + + case EEZE_UDEV_TYPE_NET: + udev_monitor_filter_add_match_subsystem_devtype(mon, "net", NULL); + break; + + case EEZE_UDEV_TYPE_IS_IT_HOT_OR_IS_IT_COLD_SENSOR: + udev_monitor_filter_add_match_subsystem_devtype(mon, "hwmon", NULL); + break; + + /* + case EEZE_UDEV_TYPE_ANDROID: + udev_monitor_filter_add_match_subsystem_devtype(mon, "input", "usb_interface"); + break; + */ + + case EEZE_UDEV_TYPE_V4L: + udev_monitor_filter_add_match_subsystem_devtype(mon, "video4linux", + NULL); + break; + + case EEZE_UDEV_TYPE_BLUETOOTH: + udev_monitor_filter_add_match_subsystem_devtype(mon, "bluetooth", + NULL); + break; + + default: + break; + } + +#endif + + if (udev_monitor_enable_receiving(mon)) + goto error; + + fd = udev_monitor_get_fd(mon); + store->func = cb; + store->data = user_data; + store->mon = mon; + store->type = type; + store->watch = watch; + store->event = event; + + if (!(handler = ecore_main_fd_handler_add(fd, ECORE_FD_READ, + _get_syspath_from_watch, store, NULL, NULL))) + goto error; + + watch->mon = mon; + watch->handler = handler; + return watch; +error: + if (store) + free(store); + if (watch) + free(watch); + if (mon) + udev_monitor_unref(mon); + ERR("Could not create watch!"); + return NULL; +} + +EAPI void * +eeze_udev_watch_del(Eeze_Udev_Watch *watch) +{ + struct _store_data *sdata; + void *ret = NULL; + + if ((!watch) || (!watch->mon) || (!watch->handler)) + return NULL; + + sdata = ecore_main_fd_handler_del(watch->handler); + udev_monitor_unref(watch->mon); + + if (sdata) + { + ret = sdata->data; + free(sdata); + } + + free(watch); + return ret; +} |