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