summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/libirecovery.h12
-rw-r--r--src/irecovery.c24
-rw-r--r--src/libirecovery.c77
3 files changed, 81 insertions, 32 deletions
diff --git a/include/libirecovery.h b/include/libirecovery.h
index 680448f..f977ebb 100644
--- a/include/libirecovery.h
+++ b/include/libirecovery.h
@@ -32,10 +32,13 @@ typedef enum {
IRECV_ERROR_USB_CONFIGURATION = -10
} irecv_error_t;
+#define APPLE_VENDOR_ID 0x05AC
+
typedef enum {
- kAppleId = 0x05AC,
- kKernelMode = 0x1294,
- kRecoveryMode = 0x1281,
+ kRecoveryMode1 = 0x1280,
+ kRecoveryMode2 = 0x1281,
+ kRecoveryMode3 = 0x1282,
+ kRecoveryMode4 = 0x1283,
kDfuMode = 0x1227
} irecv_mode_t;
@@ -50,6 +53,7 @@ struct irecv_device {
int config;
int interface;
int alt_interface;
+ char *uuid;
irecv_mode_t mode;
libusb_context* context;
libusb_device_handle* handle;
@@ -59,7 +63,7 @@ struct irecv_device {
irecv_device_t* irecv_init();
const char* irecv_strerror(irecv_error_t error);
-irecv_error_t irecv_open(irecv_device_t* device);
+irecv_error_t irecv_open(irecv_device_t* device, const char *uuid);
irecv_error_t irecv_exit(irecv_device_t* device);
irecv_error_t irecv_reset(irecv_device_t* device);
irecv_error_t irecv_close(irecv_device_t* device);
diff --git a/src/irecovery.c b/src/irecovery.c
index 1c4957e..56b0453 100644
--- a/src/irecovery.c
+++ b/src/irecovery.c
@@ -52,8 +52,10 @@ void parse_command(irecv_device_t* device, unsigned char* command, unsigned int
} else
if(!strcmp(cmd, "/reconnect")) {
+ char* uuid = strdup(device->uuid);
irecv_close(device);
- irecv_open(device);
+ irecv_open(device, uuid);
+ free(uuid);
} else
if(!strcmp(cmd, "/upload")) {
@@ -151,6 +153,7 @@ void print_usage() {
printf("iRecovery - iDevice Recovery Utility\n");
printf("Usage: ./irecovery [args]\n");
printf("\t-v\t\tStart irecovery in verbose mode.\n");
+ printf("\t-u <uuid>\ttarget specific device by its 40-digit device UUID\n");
printf("\t-c <cmd>\tSend command to device.\n");
printf("\t-f <file>\tSend file to device.\n");
printf("\t-h\t\tShow this help.\n");
@@ -163,9 +166,10 @@ int main(int argc, char** argv) {
int opt = 0;
int action = 0;
char* argument = NULL;
+ char *uuid = NULL;
irecv_error_t error = 0;
if(argc == 1) print_usage();
- while ((opt = getopt(argc, argv, "vhrsc:f:")) > 0) {
+ while ((opt = getopt(argc, argv, "vhru:sc:f:")) > 0) {
switch (opt) {
case 'v':
verbose += 1;
@@ -179,6 +183,10 @@ int main(int argc, char** argv) {
action = kResetDevice;
break;
+ case 'u':
+ uuid = optarg;
+ break;
+
case 's':
action = kStartShell;
break;
@@ -195,7 +203,7 @@ int main(int argc, char** argv) {
default:
fprintf(stderr, "Unknown argument\n");
- break;
+ return -1;
}
}
@@ -209,14 +217,16 @@ int main(int argc, char** argv) {
int i = 0;
for(i = 0; i <= 5; i++) {
debug("Attempting to connect... ");
+
+ if(irecv_open(device, uuid) < 0) sleep(1);
+ else break;
+
+ debug("failed. No recovery device found.\n");
+
if(i == 5) {
irecv_exit(device);
return -1;
}
-
- if(irecv_open(device) < 0) sleep(1);
- else break;
- debug("failed\n");
}
switch(action) {
diff --git a/src/libirecovery.c b/src/libirecovery.c
index b8eb224..18097ee 100644
--- a/src/libirecovery.c
+++ b/src/libirecovery.c
@@ -58,9 +58,10 @@ irecv_device_t* irecv_init() {
return device;
}
-irecv_error_t irecv_open(irecv_device_t* device) {
+irecv_error_t irecv_open(irecv_device_t* device, const char *uuid) {
int i = 0;
int usb_device_count = 0;
+ char serial[256];
struct libusb_device* usb_device = NULL;
struct libusb_device** usb_device_list = NULL;
struct libusb_device_handle* usb_handle = NULL;
@@ -75,28 +76,58 @@ irecv_error_t irecv_open(irecv_device_t* device) {
for (i = 0; i < usb_device_count; i++) {
usb_device = usb_device_list[i];
libusb_get_device_descriptor(usb_device, &usb_descriptor);
- if (usb_descriptor.idVendor == kAppleId) {
+ if (usb_descriptor.idVendor == APPLE_VENDOR_ID) {
+ /* verify this device is in a mode we understand */
+ if (usb_descriptor.idProduct == kRecoveryMode1 ||
+ usb_descriptor.idProduct == kRecoveryMode2 ||
+ usb_descriptor.idProduct == kRecoveryMode3 ||
+ usb_descriptor.idProduct == kRecoveryMode4 ||
+ usb_descriptor.idProduct == kDfuMode) {
+
+ libusb_open(usb_device, &usb_handle);
+ if (usb_handle == NULL) {
+ libusb_free_device_list(usb_device_list, 1);
+ return IRECV_ERROR_UNABLE_TO_CONNECT;
+ }
+
+ /* get serial number */
+ if (libusb_get_string_descriptor_ascii (usb_handle, usb_descriptor.iSerialNumber, serial, sizeof(serial)) < 0) {
+ libusb_free_device_list(usb_device_list, 1);
+ libusb_close(usb_handle);
+ return IRECV_ERROR_UNABLE_TO_CONNECT;
+ }
+
+ /* match uuid if required */
+ if (uuid != NULL) {
+ if (strcmp(uuid, serial)) {
+ libusb_close(usb_handle);
+ continue;
+ }
+ }
- libusb_open(usb_device, &usb_handle);
- if (usb_handle == NULL) {
+ /* identified a valid recovery device */
libusb_free_device_list(usb_device_list, 1);
- return IRECV_ERROR_UNABLE_TO_CONNECT;
- }
- libusb_free_device_list(usb_device_list, 1);
-
- device->handle = usb_handle;
- device->mode = (irecv_mode_t) usb_descriptor.idProduct;
- error = irecv_set_configuration(device, 1);
- if(error != IRECV_SUCCESS) {
- return error;
- }
-
- error = irecv_set_interface(device, 1, 1);
- if(error != IRECV_SUCCESS) {
- return error;
+
+ device->handle = usb_handle;
+ device->uuid = strdup(serial);
+ device->mode = (irecv_mode_t) usb_descriptor.idProduct;
+
+ debug("opening UUID \"%s\"... ", device->uuid);
+
+ error = irecv_set_configuration(device, 1);
+ if(error != IRECV_SUCCESS) {
+ debug("setting configuration... ");
+ return error;
+ }
+
+ error = irecv_set_interface(device, 1, 1);
+ if(error != IRECV_SUCCESS) {
+ debug("setting interface... ");
+ return error;
+ }
+
+ return IRECV_SUCCESS;
}
-
- return IRECV_SUCCESS;
}
}
@@ -158,7 +189,11 @@ irecv_error_t irecv_close(irecv_device_t* device) {
libusb_close(device->handle);
device->handle = NULL;
}
-
+
+ if(device->uuid != NULL) {
+ free(device->uuid);
+ }
+
return IRECV_SUCCESS;
}