From 1ce6cd438244d644a63e6d1ab1dde88633bba34e Mon Sep 17 00:00:00 2001 From: Chris Michael Date: Fri, 1 Apr 2016 09:12:36 -0400 Subject: [PATCH] elput: Add API functions to open and close an input device This adds new API functions which can be called to open or close an input device and take control (or release control) of said device Signed-off-by: Chris Michael --- src/lib/elput/Elput.h | 25 +++++++ src/lib/elput/elput_logind.c | 122 +++++++++++++++++++++++++++++++++- src/lib/elput/elput_manager.c | 25 +++++++ src/lib/elput/elput_private.h | 1 + 4 files changed, 171 insertions(+), 2 deletions(-) diff --git a/src/lib/elput/Elput.h b/src/lib/elput/Elput.h index e098b138e8..44a861ce29 100644 --- a/src/lib/elput/Elput.h +++ b/src/lib/elput/Elput.h @@ -102,6 +102,31 @@ EAPI Elput_Manager *elput_manager_connect(const char *seat, unsigned int tty, Ei */ EAPI void elput_manager_disconnect(Elput_Manager *manager); +/** + * Request input manager to open a file + * + * @param manager + * @param path + * @param flags + * + * @return Filedescriptor of opened file or -1 on failure + * + * @ingroup Elput_Manager_Group + * @since 1.18 + */ +EAPI int elput_manager_open(Elput_Manager *manager, const char *path, int flags); + +/** + * Request input manager to close a file + * + * @param manager + * @param fd + * + * @ingroup Elput_Manager_Group + * @since 1.18 + */ +EAPI void elput_manager_close(Elput_Manager *manager, int fd); + # endif # undef EAPI diff --git a/src/lib/elput/elput_logind.c b/src/lib/elput/elput_logind.c index d649bf34ea..ec3cb7ea75 100644 --- a/src/lib/elput/elput_logind.c +++ b/src/lib/elput/elput_logind.c @@ -302,6 +302,78 @@ end: eldbus_proxy_unref(proxy); } +static int +_logind_device_take(Elput_Manager *em, uint32_t major, uint32_t minor) +{ + Eldbus_Proxy *proxy; + Eldbus_Message *msg, *reply; + Eina_Bool p = EINA_FALSE; + const char *errname, *errmsg; + int fd = -1; + + proxy = + eldbus_proxy_get(em->dbus.obj, "org.freedesktop.login1.Session"); + if (!proxy) + { + ERR("Could not get dbus proxy"); + return -1; + } + + msg = eldbus_proxy_method_call_new(proxy, "TakeDevice"); + if (!msg) + { + ERR("Could not create method call for proxy"); + goto err; + } + + eldbus_message_arguments_append(msg, "uu", major, minor); + + reply = eldbus_proxy_send_and_block(proxy, msg, -1); + if (eldbus_message_error_get(reply, &errname, &errmsg)) + { + ERR("Eldbus Message Error: %s %s", errname, errmsg); + goto err; + } + + if (!eldbus_message_arguments_get(reply, "hb", &fd, &p)) + ERR("Could not get UNIX_FD from dbus message"); + + eldbus_message_unref(reply); + +err: + eldbus_proxy_unref(proxy); + return fd; +} + +static void +_logind_device_release(Elput_Manager *em, uint32_t major, uint32_t minor) +{ + Eldbus_Proxy *proxy; + Eldbus_Message *msg; + + proxy = + eldbus_proxy_get(em->dbus.obj, "org.freedesktop.login1.Session"); + if (!proxy) + { + ERR("Could not get proxy for session"); + return; + } + + msg = eldbus_proxy_method_call_new(proxy, "ReleaseDevice"); + if (!msg) + { + ERR("Could not create method call for proxy"); + goto end; + } + + eldbus_message_arguments_append(msg, "uu", major, minor); + + eldbus_proxy_send(proxy, msg, NULL, NULL, -1); + +end: + eldbus_proxy_unref(proxy); +} + static Eina_Bool _logind_activate(Elput_Manager *em) { @@ -437,12 +509,58 @@ _logind_disconnect(Elput_Manager *em) free(em); } +static int +_logind_open(Elput_Manager *em, const char *path, int flags) +{ + struct stat st; + int ret, fd = -1; + int fl; + + ret = stat(path, &st); + if (ret < 0) return -1; + + if (!S_ISCHR(st.st_mode)) return -1; + + fd = _logind_device_take(em, major(st.st_rdev), minor(st.st_rdev)); + if (fd < 0) return fd; + + fl = fcntl(fd, F_GETFL); + if (fl < 0) goto err; + + if (flags & O_NONBLOCK) + fl |= O_NONBLOCK; + + ret = fcntl(fd, F_SETFL, fl); + if (ret < 0) goto err; + + return fd; + +err: + close(fd); + _logind_device_release(em, major(st.st_rdev), minor(st.st_rdev)); + return -1; +} + +static void +_logind_close(Elput_Manager *em, int fd) +{ + struct stat st; + int ret; + + ret = fstat(fd, &st); + if (ret < 0) return; + + if (!S_ISCHR(st.st_mode)) return; + + _logind_device_release(em, major(st.st_rdev), minor(st.st_rdev)); +} + Elput_Interface _logind_interface = { _logind_connect, _logind_disconnect, - NULL, - NULL, + _logind_open, + _logind_close, NULL, NULL, }; diff --git a/src/lib/elput/elput_manager.c b/src/lib/elput/elput_manager.c index 2073ff78f9..3dc67d9594 100644 --- a/src/lib/elput/elput_manager.c +++ b/src/lib/elput/elput_manager.c @@ -37,3 +37,28 @@ elput_manager_disconnect(Elput_Manager *manager) if (manager->interface->disconnect) manager->interface->disconnect(manager); } + +EAPI int +elput_manager_open(Elput_Manager *manager, const char *path, int flags) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(manager, -1); + EINA_SAFETY_ON_NULL_RETURN_VAL(manager->interface, -1); + EINA_SAFETY_ON_NULL_RETURN_VAL(path, -1); + + if (flags < 0) flags = O_RDWR; + + if (manager->interface->open) + return manager->interface->open(manager, path, flags); + + return -1; +} + +EAPI void +elput_manager_close(Elput_Manager *manager, int fd) +{ + EINA_SAFETY_ON_NULL_RETURN(manager); + EINA_SAFETY_ON_NULL_RETURN(manager->interface); + + if (manager->interface->close) + manager->interface->close(manager, fd); +} diff --git a/src/lib/elput/elput_private.h b/src/lib/elput/elput_private.h index 07e147bcf5..74532d57d9 100644 --- a/src/lib/elput/elput_private.h +++ b/src/lib/elput/elput_private.h @@ -12,6 +12,7 @@ # include "Eldbus.h" # include +# include # include # include # include