summaryrefslogtreecommitdiff
path: root/src/lib/elput/elput_root.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/elput/elput_root.c')
-rw-r--r--src/lib/elput/elput_root.c146
1 files changed, 146 insertions, 0 deletions
diff --git a/src/lib/elput/elput_root.c b/src/lib/elput/elput_root.c
new file mode 100644
index 0000000000..f07d46d0b1
--- /dev/null
+++ b/src/lib/elput/elput_root.c
@@ -0,0 +1,146 @@
+#include "elput_private.h"
+#include <grp.h>
+#include <sys/types.h>
+#include <pwd.h>
+
+# ifdef major
+# define MAJOR(x) major(x)
+# else
+# define MAJOR(x) ((((x) >> 8) & 0xfff) | (((x) >> 32) & ~0xfff))
+# endif
+
+static Eina_Bool
+_user_part_of_input(void)
+{
+ uid_t user = getuid();
+ struct passwd *user_pw = getpwuid(user);
+ gid_t *gids = NULL;
+ int number_of_groups = 0;
+ struct group *input_group = getgrnam("input");
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(user_pw, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(input_group, EINA_FALSE);
+
+ if (getgrouplist(user_pw->pw_name, getgid(), NULL, &number_of_groups) != -1)
+ {
+ ERR("Failed to enumerate groups of user");
+ return EINA_FALSE;
+ }
+ number_of_groups ++;
+ gids = alloca((number_of_groups) * sizeof(gid_t));
+ if (getgrouplist(user_pw->pw_name, getgid(), gids, &number_of_groups) == -1)
+ {
+ ERR("Failed to get groups of user");
+ return EINA_FALSE;
+ }
+
+ for (int i = 0; i < number_of_groups; ++i)
+ {
+ if (gids[i] == input_group->gr_gid)
+ return EINA_TRUE;
+ }
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_root_connect(Elput_Manager **manager EINA_UNUSED, const char *seat EINA_UNUSED, unsigned int tty EINA_UNUSED)
+{
+ Elput_Manager *em;
+
+ em = calloc(1, sizeof(Elput_Manager));
+ if (!em) return EINA_FALSE;
+
+ em->interface = &_root_interface;
+ em->seat = eina_stringshare_add(seat);
+
+ if (!_user_part_of_input())
+ {
+ free(em);
+ return EINA_FALSE;
+ }
+ *manager = em;
+ return EINA_TRUE;
+}
+
+static void
+_root_disconnect(Elput_Manager *em EINA_UNUSED)
+{
+ //Nothing to do here, there is no data to free
+}
+
+static int
+_root_open(Elput_Manager *em EINA_UNUSED, 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 = open(path, flags);
+ if (fd < 0) return fd;
+
+ if (MAJOR(st.st_rdev) == 226) //DRM_MAJOR
+ em->drm_opens++;
+
+ 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);
+ return -1;
+}
+
+static void
+_root_open_async(Elput_Manager *em, const char *path, int flags)
+{
+ int fd = _root_open(em, path, flags);
+ int ret;
+
+ while (1)
+ {
+ ret = write(em->input.pipe, &fd, sizeof(int));
+ if (ret < 0)
+ {
+ if ((errno == EAGAIN) || (errno == EINTR))
+ continue;
+ WRN("Failed to write to input pipe");
+ }
+ break;
+ }
+ close(em->input.pipe);
+ em->input.pipe = -1;
+}
+
+static void
+_root_close(Elput_Manager *em EINA_UNUSED, int fd)
+{
+ close(fd);
+}
+
+static Eina_Bool
+_root_vt_set(Elput_Manager *em EINA_UNUSED, int vt EINA_UNUSED)
+{
+ //Nothing to do here
+ return EINA_TRUE;
+}
+
+Elput_Interface _root_interface =
+{
+ _root_connect,
+ _root_disconnect,
+ _root_open,
+ _root_open_async,
+ _root_close,
+ _root_vt_set,
+};