From c9e2fc434e2d477be0a1c2e2c5f19bcbe715aa80 Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Sat, 29 Jan 2011 04:21:53 +0000 Subject: [PATCH] eeze 1.1 in trunk: disk mounting is now possible SVN revision: 56362 --- legacy/eeze/ChangeLog | 41 +- legacy/eeze/configure.ac | 39 +- legacy/eeze/m4/ac_attribute.m4 | 47 +++ legacy/eeze/src/bin/Makefile.am | 27 +- legacy/eeze/src/bin/eeze_disk_ls.c | 53 +++ legacy/eeze/src/bin/eeze_mount.c | 115 ++++++ legacy/eeze/src/bin/eeze_umount.c | 111 ++++++ legacy/eeze/src/lib/Eeze_Disk.h | 117 ++++++ legacy/eeze/src/lib/Makefile.am | 25 +- legacy/eeze/src/lib/eeze_disk.c | 466 +++++++++++++++++++++++ legacy/eeze/src/lib/eeze_disk_libmount.c | 405 ++++++++++++++++++++ legacy/eeze/src/lib/eeze_disk_mount.c | 345 +++++++++++++++++ legacy/eeze/src/lib/eeze_disk_private.h | 78 ++++ legacy/eeze/src/lib/eeze_main.c | 46 ++- legacy/eeze/src/lib/eeze_udev_private.h | 4 +- 15 files changed, 1905 insertions(+), 14 deletions(-) create mode 100644 legacy/eeze/m4/ac_attribute.m4 create mode 100644 legacy/eeze/src/bin/eeze_disk_ls.c create mode 100644 legacy/eeze/src/bin/eeze_mount.c create mode 100644 legacy/eeze/src/bin/eeze_umount.c create mode 100644 legacy/eeze/src/lib/Eeze_Disk.h create mode 100644 legacy/eeze/src/lib/eeze_disk.c create mode 100644 legacy/eeze/src/lib/eeze_disk_libmount.c create mode 100644 legacy/eeze/src/lib/eeze_disk_mount.c create mode 100644 legacy/eeze/src/lib/eeze_disk_private.h diff --git a/legacy/eeze/ChangeLog b/legacy/eeze/ChangeLog index 6b12e82529..4e6f8188d7 100644 --- a/legacy/eeze/ChangeLog +++ b/legacy/eeze/ChangeLog @@ -1,4 +1,43 @@ +2010-01-29 Mike Blumenkrantz (discomfitor/zmike) ++Eeze_Disk_Type enum ++Eeze_Mount_Opts enum + ++EEZE_EVENT_DISK_MOUNT ++EEZE_EVENT_DISK_UNMOUNT ++EEZE_EVENT_DISK_ERROR + ++Eeze_Event_Disk_Mount struct ++Eeze_Event_Disk_Unmount struct ++Eeze_Event_Disk_Error struct + ++the following functions: +EAPI void eeze_disk_function(void); +EAPI Eeze_Disk *eeze_disk_new(const char *path); +EAPI Eeze_Disk *eeze_disk_new_from_mount(const char *mount_point); +EAPI void eeze_disk_free(Eeze_Disk *disk); +EAPI void eeze_disk_scan(Eeze_Disk *disk); +EAPI void eeze_disk_data_set(Eeze_Disk *disk, void *data); +EAPI void *eeze_disk_data_get(Eeze_Disk *disk); +EAPI const char *eeze_disk_syspath_get(Eeze_Disk *disk); +EAPI const char *eeze_disk_devpath_get(Eeze_Disk *disk); +EAPI const char *eeze_disk_fstype_get(Eeze_Disk *disk); +EAPI const char *eeze_disk_vendor_get(Eeze_Disk *disk); +EAPI const char *eeze_disk_model_get(Eeze_Disk *disk); +EAPI const char *eeze_disk_serial_get(Eeze_Disk *disk); +EAPI const char *eeze_disk_uuid_get(Eeze_Disk *disk); +EAPI const char *eeze_disk_label_get(Eeze_Disk *disk); +EAPI Eeze_Disk_Type eeze_disk_type_get(Eeze_Disk *disk); +EAPI Eina_Bool eeze_disk_removable_get(Eeze_Disk *disk); +EAPI Eina_Bool eeze_disk_mounted_get(Eeze_Disk *disk); +EAPI Eina_Bool eeze_disk_mount(Eeze_Disk *disk); +EAPI Eina_Bool eeze_disk_unmount(Eeze_Disk *disk); +EAPI const char *eeze_disk_mount_point_get(Eeze_Disk *disk); +EAPI Eina_Bool eeze_disk_mount_point_set(Eeze_Disk *disk, const char *mount_point); +EAPI Eina_Bool eeze_mount_tabs_watch(void); +EAPI void eeze_mount_tabs_unwatch(void); +EAPI Eina_Bool eeze_mount_mtab_scan(void); +EAPI Eina_Bool eeze_mount_fstab_scan(void); + 2010-01-29 Carsten Haitzler (The Rasterman) 1.0.0 release - diff --git a/legacy/eeze/configure.ac b/legacy/eeze/configure.ac index 156ad55f5d..bfe3417f73 100644 --- a/legacy/eeze/configure.ac +++ b/legacy/eeze/configure.ac @@ -7,9 +7,6 @@ m4_define([v_rev], m4_esyscmd([(svnversion "${SVN_REPO_PATH:-.}" | grep -v expor m4_if(v_rev, [0], [m4_define([v_rev], m4_esyscmd([git log 2> /dev/null | (grep -m1 git-svn-id || echo 0) | sed -e 's/.*@\([0-9]*\).*/\1/' | tr -d '\n']))]) ##-- When released, remove the dnl on the below line dnl m4_undefine([v_rev]) -##-- When doing snapshots - change soname. remove dnl on below line -dnl dnl m4_define([relname], [ver-pre-svn-06]) -dnl m4_define([v_rel], [-release relname]) ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## m4_ifdef([v_rev], [m4_define([v_ver], [v_maj.v_min.v_mic.v_rev])], [m4_define([v_ver], [v_maj.v_min.v_mic])]) m4_define([lt_rev], m4_eval(v_maj + v_min)) @@ -67,6 +64,7 @@ requirement_eeze="ecore >= 1.0.0 eina >= 1.0.0 libudev" ### Checks for programs AC_PROG_CC AM_PROG_CC_C_O +AC_C___ATTRIBUTE__ # pkg-config PKG_PROG_PKG_CONFIG @@ -97,6 +95,33 @@ elif test $udev_version -lt 148;then AC_DEFINE([OLD_UDEV_RRRRRRRRRRRRRR],[1],[compat functionality for udev < 148]) fi +eeze_mount= +PKG_CHECK_EXISTS([mount >= 2.18.0], + [ + AC_DEFINE([HAVE_EEZE_MOUNT], [1], [Eeze is mount-capable]) + AM_CONDITIONAL([HAVE_EEZE_MOUNT], [true]) + eeze_mount="yes" + ], + AM_CONDITIONAL([HAVE_EEZE_MOUNT], [false]) +) +if test "x$eeze_mount" = "xyes";then + with_mount="/bin/mount" + with_umount="/bin/umount" + AC_ARG_WITH([mount], AS_HELP_STRING([--with-mount], [specify mount bin @<:@default=detect@:>@])) + AC_ARG_WITH([umount], AS_HELP_STRING([--with-umount], [specify umount bin @<:@default=detect@:>@])) + PKG_CHECK_MODULES([LIBMOUNT], [mount >= 2.18.0]) + PKG_CHECK_MODULES([ECORE_FILE], [ecore-file >= 1.0.0]) + + if test "x$with_mount" = "xdetect";then + AC_PATH_PROG([with_mount], [mount], AC_MSG_ERROR([mount could not be found in PATH])) + fi + AC_DEFINE_UNQUOTED([EEZE_MOUNT_BIN], ["$with_mount"], [mount bin to use]) + + if test "x$with_umount" = "xdetect";then + AC_PATH_PROG([with_umount], [umount], AC_MSG_ERROR([umount could not be found in PATH])) + fi + AC_DEFINE_UNQUOTED([EEZE_UNMOUNT_BIN], ["$with_umount"], [umount bin to use]) +fi ### Checks for header files @@ -148,7 +173,12 @@ echo "$PACKAGE $VERSION" echo "------------------------------------------------------------------------" echo echo "Configuration Options Summary:" -echo +if test "x$eeze_mount" = "xyes";then + echo + echo "Mount..................: ${with_mount}" + echo "Umount.................: ${with_umount}" + echo +fi echo "Test...................: ${have_eeze_udev_test}" echo echo "Documentation..........: ${build_doc}" @@ -161,3 +191,4 @@ echo echo "Installation...........: make install (as root if needed, with 'su' or 'sudo')" echo " prefix...............: $prefix" echo + diff --git a/legacy/eeze/m4/ac_attribute.m4 b/legacy/eeze/m4/ac_attribute.m4 new file mode 100644 index 0000000000..23479a92ac --- /dev/null +++ b/legacy/eeze/m4/ac_attribute.m4 @@ -0,0 +1,47 @@ +dnl Copyright (C) 2004-2008 Kim Woelders +dnl Copyright (C) 2008 Vincent Torri +dnl That code is public domain and can be freely used or copied. +dnl Originally snatched from somewhere... + +dnl Macro for checking if the compiler supports __attribute__ + +dnl Usage: AC_C___ATTRIBUTE__ +dnl call AC_DEFINE for HAVE___ATTRIBUTE__ and __UNUSED__ +dnl if the compiler supports __attribute__, HAVE___ATTRIBUTE__ is +dnl defined to 1 and __UNUSED__ is defined to __attribute__((unused)) +dnl otherwise, HAVE___ATTRIBUTE__ is not defined and __UNUSED__ is +dnl defined to nothing. + +AC_DEFUN([AC_C___ATTRIBUTE__], +[ + +AC_MSG_CHECKING([for __attribute__]) + +AC_CACHE_VAL([ac_cv___attribute__], + [AC_TRY_COMPILE( + [ +#include + +int func(int x); +int foo(int x __attribute__ ((unused))) +{ + exit(1); +} + ], + [], + [ac_cv___attribute__="yes"], + [ac_cv___attribute__="no"] + )]) + +AC_MSG_RESULT($ac_cv___attribute__) + +if test "x${ac_cv___attribute__}" = "xyes" ; then + AC_DEFINE([HAVE___ATTRIBUTE__], [1], [Define to 1 if your compiler has __attribute__]) + AC_DEFINE([__UNUSED__], [__attribute__((unused))], [Macro declaring a function argument to be unused]) + else + AC_DEFINE([__UNUSED__], [], [Macro declaring a function argument to be unused]) +fi + +]) + +dnl End of ac_attribute.m4 diff --git a/legacy/eeze/src/bin/Makefile.am b/legacy/eeze/src/bin/Makefile.am index 029ddc1217..2d2276035b 100644 --- a/legacy/eeze/src/bin/Makefile.am +++ b/legacy/eeze/src/bin/Makefile.am @@ -1,8 +1,33 @@ MAINTAINERCLEANFILES = Makefile.in -bin_PROGRAMS = @EEZE_UDEV_TEST_PRG@ +EEZE_CFLAGS = \ +-I$(top_srcdir)/src/lib \ +@EEZE_CFLAGS@ + EXTRA_PROGRAMS = eeze_udev_test +if HAVE_EEZE_MOUNT + DISK_PROGS = eeze_mount eeze_umount eeze_disk_ls +else + DISK_PROGS = +endif + +bin_PROGRAMS = @EEZE_UDEV_TEST_PRG@ $(DISK_PROGS) + eeze_udev_test_SOURCES = eeze_udev_test.c eeze_udev_test_CPPFLAGS = -I$(top_srcdir)/src/lib @EEZE_CFLAGS@ eeze_udev_test_LDADD = $(top_builddir)/src/lib/libeeze.la @EEZE_LIBS@ + +if HAVE_EEZE_MOUNT + eeze_mount_SOURCES = eeze_mount.c + eeze_mount_CFLAGS = -I$(top_srcdir)/src/lib $(EEZE_CFLAGS) @LIBMOUNT_CFLAGS@ @ECORE_FILE_CFLAGS@ + eeze_mount_LDADD = $(top_builddir)/src/lib/libeeze.la @LIBMOUNT_CFLAGS@ @ECORE_FILE_CFLAGS@ + + eeze_umount_SOURCES = eeze_umount.c + eeze_umount_CFLAGS = -I$(top_srcdir)/src/lib $(EEZE_CFLAGS) @LIBMOUNT_CFLAGS@ @ECORE_FILE_CFLAGS@ + eeze_umount_LDADD = $(top_builddir)/src/lib/libeeze.la @LIBMOUNT_CFLAGS@ @ECORE_FILE_CFLAGS@ + + eeze_disk_ls_SOURCES = eeze_disk_ls.c + eeze_disk_ls_CFLAGS = -I$(top_srcdir)/src/lib $(EEZE_CFLAGS) @LIBMOUNT_CFLAGS@ @ECORE_FILE_CFLAGS@ + eeze_disk_ls_LDADD = $(top_builddir)/src/lib/libeeze.la @LIBMOUNT_CFLAGS@ @ECORE_FILE_CFLAGS@ +endif diff --git a/legacy/eeze/src/bin/eeze_disk_ls.c b/legacy/eeze/src/bin/eeze_disk_ls.c new file mode 100644 index 0000000000..e0f5d6a6cc --- /dev/null +++ b/legacy/eeze/src/bin/eeze_disk_ls.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include + +/* simple app to print disks and their mount points */ + +int +main(void) +{ + Eina_List *disks; + const char *syspath; + + eeze_init(); + eeze_disk_function(); + + disks = eeze_udev_find_by_type(EEZE_UDEV_TYPE_DRIVE_MOUNTABLE, NULL); + printf("Found the following disks:\n"); + EINA_LIST_FREE(disks, syspath) + { + Eeze_Disk *disk; + + disk = eeze_disk_new(syspath); + printf("\t%s - %s:%s\n", syspath, eeze_disk_devpath_get(disk), eeze_disk_mount_point_get(disk)); + eeze_disk_free(disk); + eina_stringshare_del(syspath); + } + + disks = eeze_udev_find_by_type(EEZE_UDEV_TYPE_DRIVE_REMOVABLE, NULL); + printf("Found the following removable drives:\n"); + EINA_LIST_FREE(disks, syspath) + { + Eeze_Disk *disk; + + disk = eeze_disk_new(syspath); + printf("\t%s - %s:%s\n", syspath, eeze_disk_devpath_get(disk), eeze_disk_mount_point_get(disk)); + eeze_disk_free(disk); + eina_stringshare_del(syspath); + } + + disks = eeze_udev_find_by_type(EEZE_UDEV_TYPE_DRIVE_INTERNAL, NULL); + printf("Found the following internal drives:\n"); + EINA_LIST_FREE(disks, syspath) + { + Eeze_Disk *disk; + + disk = eeze_disk_new(syspath); + printf("\t%s - %s\n", syspath, eeze_disk_devpath_get(disk)); + eeze_disk_free(disk); + eina_stringshare_del(syspath); + } + return 0; +} diff --git a/legacy/eeze/src/bin/eeze_mount.c b/legacy/eeze/src/bin/eeze_mount.c new file mode 100644 index 0000000000..84b34bf99a --- /dev/null +++ b/legacy/eeze/src/bin/eeze_mount.c @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include +#include + +/** This app can be used as a "dumb" replacement for mount. Just don't try anything fancy yet! */ +static const Ecore_Getopt opts = +{ + "eeze_mount", + "eeze_mount /dev/sdb1 /media/disk", + "1.0", + "(C) 2010 Mike Blumenkrantz", + "LGPL", + "Mount a disk using either its /sys/ path or its /dev/ path\n\n", + 1, + { + ECORE_GETOPT_VERSION('V', "version"), + ECORE_GETOPT_COPYRIGHT('R', "copyright"), + ECORE_GETOPT_LICENSE('L', "license"), + ECORE_GETOPT_HELP('h', "help"), + ECORE_GETOPT_SENTINEL + } +}; + +void +_mount_cb(void *data, int type, Eeze_Event_Disk_Mount *e) +{ + (void)data; + (void)type; + printf("Success!\n"); + eeze_disk_free(e->disk); + ecore_main_loop_quit(); +} + +void +_error_cb(void *data, int type, Eeze_Event_Disk_Error *de) +{ + (void)data; + (void)type; + printf("Could not mount disk with /dev/ path: %s!\n", eeze_disk_devpath_get(de->disk)); + eeze_disk_free(de->disk); + ecore_main_loop_quit(); +} + +int +main(int argc, char *argv[]) +{ + int args; + const char *dev, *mount_point; + Eina_Bool exit_option = EINA_FALSE; + Eeze_Disk *disk; + + Ecore_Getopt_Value values[] = + { + ECORE_GETOPT_VALUE_BOOL(exit_option), + ECORE_GETOPT_VALUE_BOOL(exit_option), + ECORE_GETOPT_VALUE_BOOL(exit_option), + ECORE_GETOPT_VALUE_BOOL(exit_option) + }; + + if (argc < 2) + { + printf("Insufficient args specified!\n"); + ecore_getopt_help(stderr, &opts); + exit(1); + } + + ecore_init(); + eeze_init(); + ecore_app_args_set(argc, (const char **)argv); + args = ecore_getopt_parse(&opts, values, argc, argv); + + if (exit_option) + return 0; + + if (args < 0) + { + printf("No args specified!\n"); + ecore_getopt_help(stderr, &opts); + exit(1); + } + + dev = argv[args]; + if (args + 1 < argc) + mount_point = argv[args + 1]; + if ((!strncmp(dev, "/sys/", 5)) || (!strncmp(dev, "/dev/", 5))) + disk = eeze_disk_new(dev); + else if ((argc == 2) && (ecore_file_is_dir(dev))) + disk = eeze_disk_new_from_mount(dev); + else + { + printf("[Device] must be either a /dev/ path or a /sys/ path!\n"); + ecore_getopt_help(stderr, &opts); + exit(1); + } + if (eeze_disk_mounted_get(disk)) + { + printf("[%s] is already mounted!", dev); + exit(1); + } + if (argc > 2) + eeze_disk_mount_point_set(disk, mount_point); + ecore_event_handler_add(EEZE_EVENT_DISK_MOUNT, (Ecore_Event_Handler_Cb)_mount_cb, NULL); + ecore_event_handler_add(EEZE_EVENT_DISK_ERROR, (Ecore_Event_Handler_Cb)_error_cb, NULL); + if (!eeze_disk_mount(disk)) + { + printf("Mount operation could not be started!\n"); + exit(1); + } + ecore_main_loop_begin(); + + return 0; +} diff --git a/legacy/eeze/src/bin/eeze_umount.c b/legacy/eeze/src/bin/eeze_umount.c new file mode 100644 index 0000000000..8025f1d09f --- /dev/null +++ b/legacy/eeze/src/bin/eeze_umount.c @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include +#include + +/** This app can be used as a "dumb" replacement for unmount. Just don't try anything fancy yet! */ +static const Ecore_Getopt opts = +{ + "eeze_unmount", + "eeze_unmount /dev/sdb1 /media/disk", + "1.0", + "(C) 2010 Mike Blumenkrantz", + "LGPL", + "unmount a disk using either its /sys/ path or its /dev/ path\n\n", + 1, + { + ECORE_GETOPT_VERSION('V', "version"), + ECORE_GETOPT_COPYRIGHT('R', "copyright"), + ECORE_GETOPT_LICENSE('L', "license"), + ECORE_GETOPT_HELP('h', "help"), + ECORE_GETOPT_SENTINEL + } +}; + +void +_unmount_cb(void *data, int type, Eeze_Event_Disk_Unmount *e) +{ + (void)data; + (void)type; + printf("Success!\n"); + eeze_disk_free(e->disk); + ecore_main_loop_quit(); +} + +void +_error_cb(void *data, int type, Eeze_Event_Disk_Error *de) +{ + (void)data; + (void)type; + printf("Could not unmount disk with /dev/ path: %s!\n", eeze_disk_devpath_get(de->disk)); + eeze_disk_free(de->disk); + ecore_main_loop_quit(); +} + +int +main(int argc, char *argv[]) +{ + int args; + const char *dev; + Eina_Bool exit_option = EINA_FALSE; + Eeze_Disk *disk; + + Ecore_Getopt_Value values[] = + { + ECORE_GETOPT_VALUE_BOOL(exit_option), + ECORE_GETOPT_VALUE_BOOL(exit_option), + ECORE_GETOPT_VALUE_BOOL(exit_option), + ECORE_GETOPT_VALUE_BOOL(exit_option) + }; + + if (argc < 2) + { + printf("Insufficient args specified!\n"); + ecore_getopt_help(stderr, &opts); + exit(1); + } + + ecore_init(); + eeze_init(); + ecore_app_args_set(argc, (const char **)argv); + args = ecore_getopt_parse(&opts, values, argc, argv); + + if (exit_option) + return 0; + + if (args < 0) + { + printf("No args specified!\n"); + ecore_getopt_help(stderr, &opts); + exit(1); + } + + dev = argv[args]; + if ((!strncmp(dev, "/sys/", 5)) || (!strncmp(dev, "/dev/", 5))) + disk = eeze_disk_new(dev); + else if ((argc == 2) && (ecore_file_is_dir(dev))) + disk = eeze_disk_new_from_mount(dev); + else + { + printf("[Device] must be either a /dev/ path or a /sys/ path!\n"); + ecore_getopt_help(stderr, &opts); + exit(1); + } + if (!eeze_disk_mounted_get(disk)) + { + printf("[%s] is already unmounted!", dev); + exit(1); + } + ecore_event_handler_add(EEZE_EVENT_DISK_UNMOUNT, (Ecore_Event_Handler_Cb)_unmount_cb, NULL); + ecore_event_handler_add(EEZE_EVENT_DISK_ERROR, (Ecore_Event_Handler_Cb)_error_cb, NULL); + if (!eeze_disk_unmount(disk)) + { + printf("unmount operation could not be started!\n"); + exit(1); + } + ecore_main_loop_begin(); + + return 0; +} diff --git a/legacy/eeze/src/lib/Eeze_Disk.h b/legacy/eeze/src/lib/Eeze_Disk.h new file mode 100644 index 0000000000..abd332ed23 --- /dev/null +++ b/legacy/eeze/src/lib/Eeze_Disk.h @@ -0,0 +1,117 @@ +#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 + * + * Eeze disk functions allow you to quickly and efficiently manipulate disks + * through simple function calls. + * + * @addtogroup disk Disk + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + EEZE_DISK_TYPE_UNKNOWN = 0, /**< type could not be determined */ + EEZE_DISK_TYPE_INTERNAL = 1, /**< internal drive */ + EEZE_DISK_TYPE_CDROM = 2, /**< cdrom drive */ + EEZE_DISK_TYPE_USB = 4 /**< usb drive */ +} Eeze_Disk_Type; + +typedef enum +{ + EEZE_DISK_MOUNTOPT_DEFAULTS = 0xf0, + EEZE_DISK_MOUNTOPT_LOOP = (1 << 1) +} Eeze_Mount_Opts; + +EAPI extern int EEZE_EVENT_DISK_MOUNT; +EAPI extern int EEZE_EVENT_DISK_UNMOUNT; +EAPI extern int EEZE_EVENT_DISK_ERROR; + +typedef struct _Eeze_Event_Disk_Mount Eeze_Event_Disk_Mount; +typedef struct _Eeze_Event_Disk_Unmount Eeze_Event_Disk_Unmount; +typedef struct _Eeze_Disk Eeze_Disk; + +struct _Eeze_Event_Disk_Mount +{ + Eeze_Disk *disk; +}; + +struct _Eeze_Event_Disk_Unmount +{ + Eeze_Disk *disk; +}; + + +typedef struct _Eeze_Event_Disk_Error Eeze_Event_Disk_Error; + +struct _Eeze_Event_Disk_Error +{ + Eeze_Disk *disk; + const char *message; + struct + { /* probably switching this to enum */ + Eina_Bool mount : 1; + Eina_Bool unmount :1; + } type; +}; + +EAPI void eeze_disk_function(void); +EAPI Eeze_Disk *eeze_disk_new(const char *path); +EAPI Eeze_Disk *eeze_disk_new_from_mount(const char *mount_point); +EAPI void eeze_disk_free(Eeze_Disk *disk); +EAPI void eeze_disk_scan(Eeze_Disk *disk); +EAPI void eeze_disk_data_set(Eeze_Disk *disk, void *data); +EAPI void *eeze_disk_data_get(Eeze_Disk *disk); +EAPI const char *eeze_disk_syspath_get(Eeze_Disk *disk); +EAPI const char *eeze_disk_devpath_get(Eeze_Disk *disk); +EAPI const char *eeze_disk_fstype_get(Eeze_Disk *disk); +EAPI const char *eeze_disk_vendor_get(Eeze_Disk *disk); +EAPI const char *eeze_disk_model_get(Eeze_Disk *disk); +EAPI const char *eeze_disk_serial_get(Eeze_Disk *disk); +EAPI const char *eeze_disk_uuid_get(Eeze_Disk *disk); +EAPI const char *eeze_disk_label_get(Eeze_Disk *disk); +EAPI Eeze_Disk_Type eeze_disk_type_get(Eeze_Disk *disk); +EAPI Eina_Bool eeze_disk_removable_get(Eeze_Disk *disk); + +EAPI Eina_Bool eeze_disk_mounted_get(Eeze_Disk *disk); +EAPI Eina_Bool eeze_disk_mount(Eeze_Disk *disk); +EAPI Eina_Bool eeze_disk_unmount(Eeze_Disk *disk); +EAPI const char *eeze_disk_mount_point_get(Eeze_Disk *disk); +EAPI Eina_Bool eeze_disk_mount_point_set(Eeze_Disk *disk, const char *mount_point); + +EAPI Eina_Bool eeze_mount_tabs_watch(void); +EAPI void eeze_mount_tabs_unwatch(void); +EAPI Eina_Bool eeze_mount_mtab_scan(void); +EAPI Eina_Bool eeze_mount_fstab_scan(void); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif diff --git a/legacy/eeze/src/lib/Makefile.am b/legacy/eeze/src/lib/Makefile.am index 0633d00b35..504b0d7ede 100644 --- a/legacy/eeze/src/lib/Makefile.am +++ b/legacy/eeze/src/lib/Makefile.am @@ -2,19 +2,34 @@ MAINTAINERCLEANFILES = Makefile.in AM_CPPFLAGS = @EEZE_CFLAGS@ +if HAVE_EEZE_MOUNT + AM_CFLAGS = @EEZE_CFLAGS@ @LIBMOUNT_CFLAGS@ @ECORE_FILE_CFLAGS@ + MOUNT_FILES = eeze_disk.c eeze_disk_mount.c eeze_disk_libmount.c + MOUNT_INCLUDES = Eeze_Disk.h +else + AM_CFLAGS = @EEZE_CFLAGS@ @LIBUDEV_CFLAGS@ + MOUNT_FILES = + MOUNT_INCLUDES = +endif + lib_LTLIBRARIES = libeeze.la -includes_HEADERS = Eeze.h +includes_HEADERS = Eeze.h $(MOUNT_INCLUDES) includesdir = $(includedir)/eeze-@VMAJ@ libeeze_la_SOURCES = \ -eeze_udev_syspath.c \ -eeze_udev_watch.c \ eeze_main.c \ eeze_udev_find.c \ +eeze_udev_private.c \ +eeze_udev_syspath.c \ eeze_udev_walk.c \ -eeze_udev_private.c +eeze_udev_watch.c \ +$(MOUNT_FILES) -libeeze_la_LIBADD = @EEZE_LIBS@ +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@ EXTRA_DIST = eeze_udev_private.h diff --git a/legacy/eeze/src/lib/eeze_disk.c b/legacy/eeze/src/lib/eeze_disk.c new file mode 100644 index 0000000000..99d6bb07de --- /dev/null +++ b/legacy/eeze/src/lib/eeze_disk.c @@ -0,0 +1,466 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "eeze_udev_private.h" +#include "eeze_disk_private.h" + +/** + * @addtogroup disk Disk + * @{ + */ + +static Eeze_Disk_Type +_eeze_disk_type_find(Eeze_Disk *disk) +{ + const char *bus; + bus = udev_device_get_property_value(disk->device, "ID_BUS"); + if (!bus) + return EEZE_DISK_TYPE_UNKNOWN; + + if (!strcmp(bus, "ata") || !strcmp(bus, "scsi")) + { /* FIXME: I think some other types of devices fall into this, check later */ + if (udev_device_get_property_value(disk->device, "ID_CDROM")) + return EEZE_DISK_TYPE_CDROM; + else + return EEZE_DISK_TYPE_INTERNAL; + } + else if (!strcmp(bus, "usb")) + return EEZE_DISK_TYPE_USB; + + return EEZE_DISK_TYPE_UNKNOWN; +} + +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; + 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; + +} + +/** + * @brief Use this function to determine whether your eeze is disk-capable + * + * Since applications will die if they run against a function that doesn't exist, + * if your application successfully runs this function then you have eeze_disk. + */ +EAPI void +eeze_disk_function(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 #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. + */ +EAPI Eeze_Disk * +eeze_disk_new(const char *path) +{ + Eeze_Disk *disk; + _udev_device *dev; + const char *syspath; + 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_cmd_changed = EINA_TRUE; + disk->unmount_cmd_changed = EINA_TRUE; + + return disk; +} + +/** + * @brief Create a new disk object from a mount point + * @param mount_point The mount point of the disk; CANNOT be #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. + */ +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 += 4; + uuid = eina_stringshare_add(source); + dev = _eeze_disk_device_from_property(uuid, EINA_TRUE); + } + else if (source[5] == '=') + { + source += 5; + label = eina_stringshare_add(source); + dev = _eeze_disk_device_from_property(label, EINA_FALSE); + } + else + { + devpath = eina_stringshare_add(source); + dev = _new_device(devpath); + } + + 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; + + 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; +} + +/** + * @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. + */ +EAPI void +eeze_disk_free(Eeze_Disk *disk) +{ + EINA_SAFETY_ON_NULL_RETURN(disk); + + eina_stringshare_del(disk->syspath); + 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); + free(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. + */ +EAPI void +eeze_disk_scan(Eeze_Disk *disk) +{ + 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.model) + disk->cache.model = udev_device_get_property_value(disk->device, "ID_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"); + disk->cache.removable = !!strtol(udev_device_get_sysattr_value(disk->device, "removable"), NULL, 10); + + disk->cache.filled = EINA_TRUE; +} + +/** + * @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 + */ +EAPI void +eeze_disk_data_set(Eeze_Disk *disk, void *data) +{ + EINA_SAFETY_ON_NULL_RETURN(disk); + + disk->data = 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 + */ +EAPI void * +eeze_disk_data_get(Eeze_Disk *disk) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL); + + return disk->data; +} + +/** + * @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. + */ +EAPI const char * +eeze_disk_syspath_get(Eeze_Disk *disk) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL); + + return disk->syspath; +} + +/** + * @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. + */ +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; +} + +/** + * @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 #NULL if unknown. + */ +EAPI const char * +eeze_disk_fstype_get(Eeze_Disk *disk) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(disk, NULL); + + return disk->fstype; +} + +/** + * @brief Return the manufacturing vendor of the disk + * @param disk The disk + * @return The vendor + * + * This retrieves the vendor which manufactured the disk, or #NULL if unknown. + */ +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"); + return disk->cache.vendor; +} + +/** + * @brief Return the model of the disk + * @param disk The disk + * @return The model + * + * This retrieves the model of the disk, or #NULL if unknown. + */ +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"); + return disk->cache.model; +} + +/** + * @brief Return the serial number of the disk + * @param disk The disk + * @return The serial number + * + * This retrieves the serial number the disk, or #NULL if unknown. + */ +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; +} + +/** + * @brief Return the UUID of the disk + * @param disk The disk + * @return The UUID + * + * This retrieves the UUID of the disk, or #NULL if unknown. + * A UUID is a 36 character (hopefully) unique identifier which can + * be used to store persistent information about a disk. + */ +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; +} + +/** + * @brief Return the label of the disk + * @param disk The disk + * @return The label + * + * This retrieves the label (name) of the disk, or #NULL if unknown. + */ +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; +} + +/** + * @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. + */ +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) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE); + + if (disk->cache.filled) + return disk->cache.removable; + + disk->cache.removable = !!strtol(udev_device_get_sysattr_value(disk->device, "removable"), NULL, 10); + return disk->cache.removable; +} + +/** @} */ diff --git a/legacy/eeze/src/lib/eeze_disk_libmount.c b/legacy/eeze/src/lib/eeze_disk_libmount.c new file mode 100644 index 0000000000..36fd9aee17 --- /dev/null +++ b/legacy/eeze/src/lib/eeze_disk_libmount.c @@ -0,0 +1,405 @@ +#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" + +/** + * @addtogroup disk Disk + * @{ + */ + +/* + * + * 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; + +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; + } + + 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); +} + +/* + * 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) + return EINA_FALSE; + + disk->mount_point = eina_stringshare_add(mnt_fs_get_target(mnt)); + 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 + * + */ + +/** + * @brief Begin watching mtab and fstab + * @return #EINA_TRUE if watching was started, else #EINA_FALSE + * + * 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 + */ +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; +} + +/** + * @brief Stop watching /etc/fstab and /etc/mtab + * + * This function stops watching fstab and mtab. Data obtained previously will be saved. + */ +EAPI void +eeze_mount_tabs_unwatch(void) +{ + if (!_watching) + return; + + ecore_file_monitor_del(_mtab_mon); + ecore_file_monitor_del(_fstab_mon); +} + +/** + * @brief Scan /etc/mtab a single time + * @return #EINA_TRUE if mtab could be scanned, else #EINA_FALSE + * + * 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, #EINA_TRUE will be returned. + * @see eeze_mount_tabs_watch, eeze_mount_fstab_scan + */ +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; +} + +/** + * @brief Scan /etc/fstab a single time + * @return #EINA_TRUE if mtab could be scanned, else #EINA_FALSE + * + * 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, #EINA_TRUE will be returned. + * @see eeze_mount_tabs_watch, eeze_mount_mtab_scan + */ +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/legacy/eeze/src/lib/eeze_disk_mount.c b/legacy/eeze/src/lib/eeze_disk_mount.c new file mode 100644 index 0000000000..e26c8fb6c0 --- /dev/null +++ b/legacy/eeze/src/lib/eeze_disk_mount.c @@ -0,0 +1,345 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "eeze_udev_private.h" +#include "eeze_disk_private.h" + +#define EEZE_MOUNT_DEFAULT_OPTS "noexec,nosuid" + +/** + * @addtogroup disk Disk + * @{ + */ + +EAPI int EEZE_EVENT_DISK_MOUNT = 0; +EAPI int EEZE_EVENT_DISK_UNMOUNT = 0; +EAPI int EEZE_EVENT_DISK_ERROR = 0; +static Ecore_Event_Handler *_mount_handler = 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: this is a placeholder since currently there are only mount-type errors */ + de->type.mount = EINA_TRUE; + 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; + Eeze_Event_Disk_Mount *e; + + if ((!ev) || (!ev->exe)) + return ECORE_CALLBACK_RENEW; + if (!(disk = ecore_exe_data_get(ev->exe))) + return ECORE_CALLBACK_RENEW; + + + if (disk->mount_status == EEZE_DISK_MOUNTING) + switch (ev->exit_code) + { + case 1: + _eeze_disk_mount_error_handler(disk, "incorrect invocation or permissions"); + break; + + case 2: + _eeze_disk_mount_error_handler(disk, "system error (out of memory, cannot fork, no more loop devices)"); + break; + + case 4: + _eeze_disk_mount_error_handler(disk, "internal mount bug"); + break; + + case 8: + _eeze_disk_mount_error_handler(disk, "user interrupt"); + break; + + case 16: + _eeze_disk_mount_error_handler(disk, "problems writing or locking /etc/mtab"); + break; + + case 32: + _eeze_disk_mount_error_handler(disk, "mount failure"); + break; + + case 64: + _eeze_disk_mount_error_handler(disk, "some mount succeeded"); + break; + + default: + 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 + 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; + ecore_event_add(EEZE_EVENT_DISK_UNMOUNT, e, NULL, NULL); + break; + + default: + INF("Could not unmount disk, retrying"); + disk->mounter = ecore_exe_pipe_run(eina_strbuf_string_get(disk->unmount_cmd), 0, disk); + return ECORE_CALLBACK_RENEW; + } + + return ECORE_CALLBACK_RENEW; +} + +/* + * + * INVISIBLE + * + */ + +Eina_Bool +eeze_mount_init(void) +{ + EEZE_EVENT_DISK_MOUNT = ecore_event_type_new(); + EEZE_EVENT_DISK_UNMOUNT = ecore_event_type_new(); + EEZE_EVENT_DISK_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 + * + */ + +/** + * @brief Return the mount state of a disk + * @param disk The disk + * @return The mount state + * + * This returns the mounted state of the disk. #EINA_TRUE if mounted, else #EINA_FALSE. + */ +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); +} + +/** + * @brief Begin a mount operation on the disk + * @param disk The disk + * @return #EINA_TRUE if the operation was started, else #EINA_FALSE + * + * 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. + */ +EAPI Eina_Bool +eeze_disk_mount(Eeze_Disk *disk) +{ + 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) + { + eina_strbuf_string_free(disk->mount_cmd); + if (!disk->cache.uuid) + disk->cache.uuid = udev_device_get_property_value(disk->device, "ID_FS_UUID"); + + if (!disk->mount_point) + { + const char *mp; + /* here we attempt to guess the mount point using libmount */ + mp = eeze_disk_libmount_mp_lookup_by_uuid(disk->cache.uuid); + if (!mp) + { + const char *label; + + label = eeze_disk_label_get(disk); + if (label) + { + mp = eeze_disk_libmount_mp_lookup_by_label(label); + eina_stringshare_del(label); + } + if (!mp) + { + const char *devpath; + + devpath = eeze_disk_devpath_get(disk); + if (devpath) + { + mp = eeze_disk_libmount_mp_lookup_by_devpath(devpath); + eina_stringshare_del(devpath); + } + } + } + if (!eeze_disk_mount_point_set(disk, mp)) + /* sometimes we fail */ + return EINA_FALSE; + } + + eina_strbuf_append_printf(disk->mount_cmd, "%s -o %s UUID=%s %s", EEZE_MOUNT_BIN, EEZE_MOUNT_DEFAULT_OPTS, disk->cache.uuid, disk->mount_point); + disk->mount_cmd_changed = EINA_FALSE; + } + + INF("Mounting: %s", eina_strbuf_string_get(disk->mount_cmd)); + disk->mounter = ecore_exe_pipe_run(eina_strbuf_string_get(disk->mount_cmd), 0, disk); + if (!disk->mounter) + return EINA_FALSE; + + disk->mount_status = EEZE_DISK_MOUNTING; + + return EINA_TRUE; +} + +/** + * @brief Begin an unmount operation on the disk + * @param disk The disk + * @return #EINA_TRUE if the operation was started, else #EINA_FALSE + * + * 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_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. + */ +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); + eina_strbuf_append_printf(disk->unmount_cmd, "%s %s", EEZE_UNMOUNT_BIN, disk->mount_point); + disk->unmount_cmd_changed = EINA_FALSE; + } + + INF("Unmounting: %s", eina_strbuf_string_get(disk->unmount_cmd)); + disk->mounter = ecore_exe_pipe_run(eina_strbuf_string_get(disk->unmount_cmd), 0, disk); + if (!disk->mounter) + return EINA_FALSE; + + disk->mount_status = EEZE_DISK_UNMOUNTING; + return EINA_TRUE; +} + +/** + * @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. + */ +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; +} + +/** + * @brief Set the mount point of a disk + * @param disk The disk + * @param mount_point The mount point + * @return EINA_TRUE on success, else EINA_FALSE + * + * 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. + */ +EAPI Eina_Bool +eeze_disk_mount_point_set(Eeze_Disk *disk, const char *mount_point) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(disk, EINA_FALSE); + + disk->mount_point = mount_point; + disk->mount_cmd_changed = EINA_TRUE; + disk->unmount_cmd_changed = EINA_TRUE; + return EINA_TRUE; +} + +/** @} */ diff --git a/legacy/eeze/src/lib/eeze_disk_private.h b/legacy/eeze/src/lib/eeze_disk_private.h new file mode 100644 index 0000000000..692e6ce3f5 --- /dev/null +++ b/legacy/eeze/src/lib/eeze_disk_private.h @@ -0,0 +1,78 @@ +#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 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_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, + EEZE_DISK_MOUNTING, + EEZE_DISK_UNMOUNTING +} Eeze_Disk_Status; + +struct _Eeze_Disk +{ + _udev_device *device; + void *data; + + Eeze_Disk_Status mount_status; + Eina_Strbuf *mount_cmd; + Eina_Strbuf *unmount_cmd; + Eina_Bool mount_cmd_changed : 1; + Eina_Bool unmount_cmd_changed : 1; + Ecore_Exe *mounter; + + const char *syspath; + const char *devpath; + const char *fstype; + const char *mount_point; + + 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_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); + +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/legacy/eeze/src/lib/eeze_main.c b/legacy/eeze/src/lib/eeze_main.c index 817873cc37..3937cae092 100644 --- a/legacy/eeze/src/lib/eeze_main.c +++ b/legacy/eeze/src/lib/eeze_main.c @@ -4,7 +4,9 @@ #include #include +#include #include "eeze_udev_private.h" +#include "eeze_disk_private.h" /** * @defgroup udev udev @@ -15,6 +17,9 @@ _udev *udev; int _eeze_udev_log_dom = -1; +#ifdef HAVE_EEZE_MOUNT +int _eeze_disk_log_dom = -1; +#endif int _eeze_init_count = 0; /** @@ -45,7 +50,7 @@ eeze_init(void) return 0; _eeze_udev_log_dom = eina_log_domain_register - ("eeze_udev", EEZE_UDEV_COLOR_DEFAULT); + ("eeze_udev", EINA_COLOR_CYAN); if (_eeze_udev_log_dom < 0) { @@ -55,16 +60,47 @@ eeze_init(void) if (!ecore_init()) goto fail; +#ifdef HAVE_EEZE_MOUNT + _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 ecore_fail; + if (!eeze_mount_init()) + goto ecore_file_fail; + +#endif if (!((udev) = udev_new())) { EINA_LOG_ERR("Could not initialize udev library!"); +#ifdef HAVE_EEZE_MOUNT + goto eeze_fail; +#else goto ecore_fail; +#endif } return _eeze_init_count; + +#ifdef HAVE_EEZE_MOUNT +eeze_fail: + eeze_mount_shutdown(); +ecore_file_fail: + ecore_file_shutdown(); +#endif ecore_fail: ecore_shutdown(); +#ifdef HAVE_EEZE_MOUNT +disk_fail: + eina_log_domain_unregister(_eeze_disk_log_dom); + _eeze_disk_log_dom = -1; +#endif fail: eina_log_domain_unregister(_eeze_udev_log_dom); _eeze_udev_log_dom = -1; @@ -89,7 +125,15 @@ eeze_shutdown(void) return _eeze_init_count; udev_unref(udev); +#ifdef HAVE_EEZE_MOUNT + eeze_mount_shutdown(); + ecore_file_shutdown(); ecore_shutdown(); + eina_log_domain_unregister(_eeze_disk_log_dom); + _eeze_disk_log_dom = -1; +#else + ecore_shutdown(); +#endif eina_log_domain_unregister(_eeze_udev_log_dom); _eeze_udev_log_dom = -1; eina_shutdown(); diff --git a/legacy/eeze/src/lib/eeze_udev_private.h b/legacy/eeze/src/lib/eeze_udev_private.h index f7ed94cd22..c17251a0d2 100644 --- a/legacy/eeze/src/lib/eeze_udev_private.h +++ b/legacy/eeze/src/lib/eeze_udev_private.h @@ -1,6 +1,6 @@ #ifndef EEZE_UDEV_PRIVATE_H #define EEZE_UDEV_PRIVATE_H -#include "Eeze.h" +#include #ifndef EEZE_UDEV_COLOR_DEFAULT #define EEZE_UDEV_COLOR_DEFAULT EINA_COLOR_CYAN @@ -20,7 +20,7 @@ extern int _eeze_udev_log_dom; #endif #define DBG(...) EINA_LOG_DOM_DBG(_eeze_udev_log_dom, __VA_ARGS__) -#define INFO(...) EINA_LOG_DOM_INFO(_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__)