/* 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; }