/* See LICENSE file for copyright and license details. */ #include "common.h" static int search(int dirfd, const char *file, size_t **cardsp, size_t *countp, struct stat *st_buf) { int fd; DIR *dir; struct dirent *f; unsigned long num; char *end; void *new; fd = openat(dirfd, file, O_DIRECTORY); if (fd < 0) return -1; dir = fdopendir(fd); if (!dir) { close(fd); return -1; } if (!strcmp(file, "sound")) { while (errno = 0, (f = readdir(dir))) { if (strncmp(f->d_name, "card", 4) || !isdigit(f->d_name[4])) continue; num = strtoul(&f->d_name[4], &end, 10); if (errno || *end) continue; if (*countp == (size_t)SSIZE_MAX) break; new = realloc(*cardsp, (*countp + 1) * sizeof(**cardsp)); if (!new) goto fail; *cardsp = new; (*cardsp)[(*countp)++] = (size_t)num; } } else { while (errno = 0, (f = readdir(dir))) { if (f->d_name[0] == '.') continue; if (fstatat(fd, f->d_name, st_buf, AT_SYMLINK_NOFOLLOW)) goto fail; if (S_ISLNK(st_buf->st_mode)) continue; search(fd, f->d_name, cardsp, countp, st_buf); } } closedir(dir); return errno ? -1 : 0; fail: closedir(dir); return -1; } ssize_t libgamepad_find_sound_devices(const char *syspath, size_t **cardsp) { int fd, i, saved_errno = errno; size_t count = 0; struct stat st; const char *p = syspath; *cardsp = NULL; if (*p != '/') return 0; for (i = 0; i < 5; i++) { p = strchr(&p[1], '/'); if (!p) return 0; } fd = open(syspath, O_DIRECTORY); if (fd < 0) return -1; if (search(fd, "../..", cardsp, &count, &st)) { close(fd); free(*cardsp); *cardsp = NULL; return -1; } close(fd); errno = saved_errno; return (ssize_t)count; }