Index: util/mtp-probe.c |
diff --git a/util/mtp-probe.c b/util/mtp-probe.c |
index 3e52086aefd3a7e71a8c9c262ae99c54192628c4..3ff20406759850031e3b11824c881daf375fb12d 100644 |
--- a/util/mtp-probe.c |
+++ b/util/mtp-probe.c |
@@ -45,7 +45,242 @@ |
#include <stdio.h> |
#include <string.h> |
#include <syslog.h> |
+#include <sys/types.h> |
+#include <sys/stat.h> |
+#include <dirent.h> |
#include <libmtp.h> |
+#include <regex.h> |
+#include <fcntl.h> |
+ |
+enum ep_type { |
+ OTHER_EP, |
+ BULK_OUT_EP, |
+ BULK_IN_EP, |
+ INTERRUPT_IN_EP, |
+ INTERRUPT_OUT_EP, |
+}; |
+ |
+static enum ep_type get_ep_type(char *path) |
+{ |
+ char pbuf[FILENAME_MAX]; |
+ int len = strlen(path); |
+ int fd; |
+ char buf[128]; |
+ int bread; |
+ int is_out = 0; |
+ int is_in = 0; |
+ int is_bulk = 0; |
+ int is_interrupt = 0; |
+ int i; |
+ |
+ strcpy(pbuf, path); |
+ pbuf[len++] = '/'; |
+ |
+ /* Check the type */ |
+ strncpy(pbuf + len, "type", FILENAME_MAX - len); |
+ pbuf[FILENAME_MAX - 1] = '\0'; /* Sentinel */ |
+ |
+ fd = open(pbuf, O_RDONLY); |
+ if (fd < 0) |
+ return OTHER_EP; |
+ bread = read(fd, buf, sizeof(buf)); |
+ close(fd); |
+ if (bread < 2) |
+ return OTHER_EP; |
+ |
+ for (i = 0; i < bread; i++) |
+ if(buf[i] == 0x0d || buf[i] == 0x0a) |
+ buf[i] = '\0'; |
+ |
+ if (!strcmp(buf, "Bulk")) |
+ is_bulk = 1; |
+ if (!strcmp(buf, "Interrupt")) |
+ is_interrupt = 1; |
+ |
+ /* Check the direction */ |
+ strncpy(pbuf + len, "direction", FILENAME_MAX - len); |
+ pbuf[FILENAME_MAX - 1] = '\0'; /* Sentinel */ |
+ |
+ fd = open(pbuf, O_RDONLY); |
+ if (fd < 0) |
+ return OTHER_EP; |
+ bread = read(fd, buf, sizeof(buf)); |
+ close(fd); |
+ if (bread < 2) |
+ return OTHER_EP; |
+ |
+ for (i = 0; i < bread; i++) |
+ if(buf[i] == 0x0d || buf[i] == 0x0a) |
+ buf[i] = '\0'; |
+ |
+ if (!strcmp(buf, "in")) |
+ is_in = 1; |
+ if (!strcmp(buf, "out")) |
+ is_out = 1; |
+ |
+ if (is_bulk && is_in) |
+ return BULK_IN_EP; |
+ if (is_bulk && is_out) |
+ return BULK_OUT_EP; |
+ if (is_interrupt && is_in) |
+ return INTERRUPT_IN_EP; |
+ if (is_interrupt && is_out) |
+ return INTERRUPT_OUT_EP; |
+ |
+ return OTHER_EP; |
+} |
+ |
+static int has_3_ep(char *path) |
+{ |
+ char pbuf[FILENAME_MAX]; |
+ int len = strlen(path); |
+ int fd; |
+ char buf[128]; |
+ int bread; |
+ |
+ strcpy(pbuf, path); |
+ pbuf[len++] = '/'; |
+ strncpy(pbuf + len, "bNumEndpoints", FILENAME_MAX - len); |
+ pbuf[FILENAME_MAX - 1] = '\0'; /* Sentinel */ |
+ |
+ fd = open(pbuf, O_RDONLY); |
+ if (fd < 0) |
+ return -1; |
+ /* Read all contents to buffer */ |
+ bread = read(fd, buf, sizeof(buf)); |
+ close(fd); |
+ if (bread < 2) |
+ return 0; |
+ |
+ /* 0x30, 0x33 = "03", maybe we should parse it? */ |
+ if (buf[0] == 0x30 && buf[1] == 0x33) |
+ return 1; |
+ |
+ return 0; |
+} |
+ |
+static int check_interface(char *sysfspath) |
+{ |
+ char dirbuf[FILENAME_MAX]; |
+ int len = strlen(sysfspath); |
+ DIR *dir; |
+ struct dirent *dent; |
+ regex_t r; |
+ int ret; |
+ int bulk_out_ep_found = 0; |
+ int bulk_in_ep_found = 0; |
+ int interrupt_in_ep_found = 0; |
+ |
+ ret = has_3_ep(sysfspath); |
+ if (ret <= 0) |
+ return ret; |
+ |
+ /* Yes it has three endpoints ... look even closer! */ |
+ dir = opendir(sysfspath); |
+ if (!dir) |
+ return -1; |
+ |
+ strcpy(dirbuf, sysfspath); |
+ dirbuf[len++] = '/'; |
+ |
+ /* Check for dirs that identify endpoints */ |
+ ret = regcomp(&r, "^ep_[0-9a-f]+$", REG_EXTENDED | REG_NOSUB); |
+ if (ret) { |
+ closedir(dir); |
+ return -1; |
+ } |
+ |
+ while ((dent = readdir(dir))) { |
+ struct stat st; |
+ |
+ /* No need to check those beginning with a period */ |
+ if (dent->d_name[0] == '.') |
+ continue; |
+ |
+ strncpy(dirbuf + len, dent->d_name, FILENAME_MAX - len); |
+ dirbuf[FILENAME_MAX - 1] = '\0'; /* Sentinel */ |
+ ret = lstat(dirbuf, &st); |
+ if (ret) |
+ continue; |
+ if (S_ISDIR(st.st_mode) && !regexec(&r, dent->d_name, 0, 0, 0)) { |
+ enum ep_type ept; |
+ |
+ ept = get_ep_type(dirbuf); |
+ if (ept == BULK_OUT_EP) |
+ bulk_out_ep_found = 1; |
+ else if (ept == BULK_IN_EP) |
+ bulk_in_ep_found = 1; |
+ else if (ept == INTERRUPT_IN_EP) |
+ interrupt_in_ep_found = 1; |
+ } |
+ } |
+ |
+ regfree(&r); |
+ closedir(dir); |
+ |
+ /* |
+ * If this is fulfilled the interface is an MTP candidate |
+ */ |
+ if (bulk_out_ep_found && |
+ bulk_in_ep_found && |
+ interrupt_in_ep_found) { |
+ return 1; |
+ } |
+ |
+ return 0; |
+} |
+ |
+static int check_sysfs(char *sysfspath) |
+{ |
+ char dirbuf[FILENAME_MAX]; |
+ int len = strlen(sysfspath); |
+ DIR *dir; |
+ struct dirent *dent; |
+ regex_t r; |
+ int ret; |
+ int look_closer = 0; |
+ |
+ dir = opendir(sysfspath); |
+ if (!dir) |
+ return -1; |
+ |
+ strcpy(dirbuf, sysfspath); |
+ dirbuf[len++] = '/'; |
+ |
+ /* Check for dirs that identify interfaces */ |
+ ret = regcomp(&r, "^[0-9]+-[0-9]+(\\.[0-9])*\\:[0-9]+\\.[0-9]+$", REG_EXTENDED | REG_NOSUB); |
+ if (ret) { |
+ closedir(dir); |
+ return -1; |
+ } |
+ |
+ while ((dent = readdir(dir))) { |
+ struct stat st; |
+ int ret; |
+ |
+ /* No need to check those beginning with a period */ |
+ if (dent->d_name[0] == '.') |
+ continue; |
+ |
+ strncpy(dirbuf + len, dent->d_name, FILENAME_MAX - len); |
+ dirbuf[FILENAME_MAX - 1] = '\0'; /* Sentinel */ |
+ ret = lstat(dirbuf, &st); |
+ if (ret) |
+ continue; |
+ |
+ /* Look closer at dirs that may be interfaces */ |
+ if (S_ISDIR(st.st_mode)) { |
+ if (!regexec(&r, dent->d_name, 0, 0, 0)) |
+ if (check_interface(dirbuf) > 0) |
+ /* potential MTP interface! */ |
+ look_closer = 1; |
+ } |
+ } |
+ |
+ regfree(&r); |
+ closedir(dir); |
+ return look_closer; |
+} |
int main (int argc, char **argv) |
{ |
@@ -66,7 +301,14 @@ int main (int argc, char **argv) |
syslog(LOG_INFO, "checking bus %d, device %d: \"%s\"\n", busno, devno, fname); |
- ret = LIBMTP_Check_Specific_Device(busno, devno); |
+ ret = check_sysfs(fname); |
+ /* |
+ * This means that regular directory check either agrees that this may be a |
+ * MTP device, or that it doesn't know (failed). In that case, kick the deeper |
+ * check inside LIBMTP. |
+ */ |
+ if (ret != 0) |
+ ret = LIBMTP_Check_Specific_Device(busno, devno); |
if (ret) { |
syslog(LOG_INFO, "bus: %d, device: %d was an MTP device\n", busno, devno); |
printf("1"); |