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