diff options
Diffstat (limited to 'libgamepad_list_superdevices.c')
-rw-r--r-- | libgamepad_list_superdevices.c | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/libgamepad_list_superdevices.c b/libgamepad_list_superdevices.c new file mode 100644 index 0000000..f8c7c4d --- /dev/null +++ b/libgamepad_list_superdevices.c @@ -0,0 +1,77 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +int +libgamepad_list_superdevices(char ***devicesp, size_t *ndevicesp) +{ + char path[PATH_MAX], target[PATH_MAX]; /* TODO do not use PATH_MAX */ + int dirfd; + DIR *dir; + struct dirent *f; + ssize_t r; + char **paths = NULL; + size_t n = 0, i; + void *new; + int saved_errno = errno; + + *devicesp = NULL; + *ndevicesp = 0; + + dirfd = open("/sys/class/input/", O_DIRECTORY); + if (dirfd < 0) + return -1; + + dir = fdopendir(dirfd); + if (!dir) { + close(dirfd); + return -1; + } + + while (errno = 0, (f = readdir(dir))) { + if (!strncmp(f->d_name, "event", 5) && isdigit(f->d_name[5])) { + stpcpy(stpcpy(stpcpy(path, "/sys/class/input/"), f->d_name), "/device/device"); + dirfd = open(path, O_PATH); + if (dirfd < 0) + continue; + sprintf(path, "/dev/fd/%i", dirfd); + r = readlink(path, target, sizeof(target) - 1); + close(dirfd); + if (r < 0) + continue; + target[r] = '\0'; + if (paths) + for (i = 0; i < n; i++) + if (!strcmp(paths[i], target)) + goto next; + stpcpy(stpcpy(path, target), "/input"); + if (access(path, F_OK)) + continue; + new = realloc(paths, (n + 1) * sizeof(*paths)); + if (!new) + goto fail; + paths = new; + paths[n] = strdup(target); + if (!paths[n]) + goto fail; + n += 1; + } + next:; + } + + if (errno) + goto fail; + closedir(dir); + + errno = saved_errno; + *devicesp = paths; + *ndevicesp = n; + return 0; + +fail: + for (i = 0; i < n; i++) + free(paths[i]); + free(paths); + closedir(dir); + return -1; +} |