1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
/* 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;
}
|