From 75cedceb190d191366c6cdec95f938f497b48aa9 Mon Sep 17 00:00:00 2001 From: raster Date: Thu, 30 Aug 2012 09:54:57 +0000 Subject: 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 --- src/lib/Eeze.h | 560 ++++++++++++++++++++++++++++++++++++++ src/lib/Eeze_Disk.h | 567 +++++++++++++++++++++++++++++++++++++++ src/lib/Eeze_Net.h | 62 +++++ src/lib/Makefile.am | 43 +++ src/lib/eeze_disk.c | 476 ++++++++++++++++++++++++++++++++ src/lib/eeze_disk_libmount.c | 495 ++++++++++++++++++++++++++++++++++ src/lib/eeze_disk_libmount_new.c | 525 ++++++++++++++++++++++++++++++++++++ src/lib/eeze_disk_libmount_old.c | 401 +++++++++++++++++++++++++++ src/lib/eeze_disk_mount.c | 465 ++++++++++++++++++++++++++++++++ src/lib/eeze_disk_private.h | 93 +++++++ src/lib/eeze_disk_udev.c | 90 +++++++ src/lib/eeze_main.c | 104 +++++++ src/lib/eeze_net.c | 321 ++++++++++++++++++++++ src/lib/eeze_net_private.h | 53 ++++ src/lib/eeze_udev_find.c | 384 ++++++++++++++++++++++++++ src/lib/eeze_udev_private.c | 200 ++++++++++++++ src/lib/eeze_udev_private.h | 46 ++++ src/lib/eeze_udev_syspath.c | 292 ++++++++++++++++++++ src/lib/eeze_udev_walk.c | 65 +++++ src/lib/eeze_udev_watch.c | 449 +++++++++++++++++++++++++++++++ 20 files changed, 5691 insertions(+) create mode 100644 src/lib/Eeze.h create mode 100644 src/lib/Eeze_Disk.h create mode 100644 src/lib/Eeze_Net.h create mode 100644 src/lib/Makefile.am create mode 100644 src/lib/eeze_disk.c create mode 100644 src/lib/eeze_disk_libmount.c create mode 100644 src/lib/eeze_disk_libmount_new.c create mode 100644 src/lib/eeze_disk_libmount_old.c create mode 100644 src/lib/eeze_disk_mount.c create mode 100644 src/lib/eeze_disk_private.h create mode 100644 src/lib/eeze_disk_udev.c create mode 100644 src/lib/eeze_main.c create mode 100644 src/lib/eeze_net.c create mode 100644 src/lib/eeze_net_private.h create mode 100644 src/lib/eeze_udev_find.c create mode 100644 src/lib/eeze_udev_private.c create mode 100644 src/lib/eeze_udev_private.h create mode 100644 src/lib/eeze_udev_syspath.c create mode 100644 src/lib/eeze_udev_walk.c create mode 100644 src/lib/eeze_udev_watch.c (limited to 'src/lib') 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) + @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 + +#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 +#include + +/** + * @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 +#include + +/** + * @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 +#include +#include + +#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 +#include +#include +#include +#include + +#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 +#include +#include +#include + +#include +#include +#include +#include +#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 +#include +#include +#include + +#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 +#include +#include +#include + +#include +#include +#include + +#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 +#include + +#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 +#include +#include + +#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 +#include +#include +#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 +#include +#include +#include +#include + +#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 +#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 +#include +#include +#include + +#include +#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 +#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 + +#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE 1 +#include + +#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 +#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 +#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 +#include +#include +#include + +#include +#include +#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; +} -- cgit v1.2.3