summaryrefslogtreecommitdiffstats
path: root/src/recovery.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/recovery.c')
-rw-r--r--src/recovery.c349
1 files changed, 231 insertions, 118 deletions
diff --git a/src/recovery.c b/src/recovery.c
index 4e2e7ad..361ce11 100644
--- a/src/recovery.c
+++ b/src/recovery.c
@@ -23,247 +23,360 @@
#include <stdlib.h>
#include <stdint.h>
#include <libirecovery.h>
+#include <libimobiledevice/restore.h>
+#include <libimobiledevice/libimobiledevice.h>
#include "tss.h"
#include "img3.h"
#include "recovery.h"
#include "idevicerestore.h"
-int recovery_send_signed_component(irecv_client_t client, char* ipsw, plist_t tss, char* component) {
+int recovery_progress_callback(irecv_client_t client, const irecv_event_t* event) {
+ if (event->type == IRECV_PROGRESS) {
+ print_progress_bar(event->data, event->progress);
+ }
+ return 0;
+}
+
+int recovery_check_mode() {
+ irecv_client_t recovery = NULL;
+ irecv_error_t recovery_error = IRECV_E_SUCCESS;
+
+ recovery_error = irecv_open(&recovery);
+ if (recovery_error != IRECV_E_SUCCESS) {
+ return -1;
+ }
+
+ if (recovery->mode == kDfuMode) {
+ irecv_close(recovery);
+ return -1;
+ }
+
+ irecv_close(recovery);
+ recovery = NULL;
+ return 0;
+}
+
+int recovery_enter_restore(const char* uuid, const char* ipsw, plist_t tss) {
+ idevice_t device = NULL;
+ restored_client_t restore = NULL;
+
+ // upload data to make device boot restore mode
+ if (recovery_send_ibec(ipsw, tss) < 0) {
+ error("ERROR: Unable to send iBEC\n");
+ return -1;
+ }
+ sleep(1);
+
+ if (recovery_send_applelogo(ipsw, tss) < 0) {
+ error("ERROR: Unable to send AppleLogo\n");
+ return -1;
+ }
+
+ if (recovery_send_devicetree(ipsw, tss) < 0) {
+ error("ERROR: Unable to send DeviceTree\n");
+ return -1;
+ }
+
+ if (recovery_send_ramdisk(ipsw, tss) < 0) {
+ error("ERROR: Unable to send Ramdisk\n");
+ return -1;
+ }
+
+ // for some reason iboot requires a hard reset after ramdisk
+ // or things start getting wacky
+ printf("Please unplug your device, then plug it back in\n");
+ printf("Hit any key to continue...");
+ getchar();
+
+ if (recovery_send_kernelcache(ipsw, tss) < 0) {
+ error("ERROR: Unable to send KernelCache\n");
+ return -1;
+ }
+
+ info("Waiting for device to enter restore mode\n");
+ if (restore_open_with_timeout(uuid, &device, &restore) < 0) {
+ error("ERROR: Unable to connect to device in restore mode\n");
+ return -1;
+ }
+
+ restore_close(device, restore);
+ idevicerestore_mode = MODE_RESTORE;
+ return 0;
+}
+
+int recovery_send_signed_component(irecv_client_t client, const char* ipsw, plist_t tss, char* component) {
int size = 0;
char* data = NULL;
char* path = NULL;
char* blob = NULL;
- img3_file* img3 = NULL;
irecv_error_t error = 0;
- if (get_signed_component_by_name(ipsw, tss, component, &data, &size) < 0) {
+ if (tss_get_entry_path(tss, component, &path) < 0) {
+ error("ERROR: Unable to get component path\n");
+ return -1;
+ }
+
+ if (get_signed_component(ipsw, tss, path, &data, &size) < 0) {
error("ERROR: Unable to get signed component: %s\n", component);
+ free(path);
return -1;
}
+ free(path);
info("Sending %s...\n", component);
error = irecv_send_buffer(client, data, size);
if (error != IRECV_E_SUCCESS) {
- error("ERROR: Unable to send IMG3: %s\n", path);
- img3_free(img3);
+ error("ERROR: Unable to send component: %s\n", component);
free(data);
- free(path);
return -1;
}
-
- if (data) {
- free(data);
- data = NULL;
- }
+ free(data);
return 0;
}
-irecv_error_t recovery_open_with_timeout(irecv_client_t* client) {
+int recovery_open_with_timeout(irecv_client_t* client) {
int i = 0;
- irecv_error_t error = 0;
- for (i = 10; i > 0; i--) {
- error = irecv_open(client);
- if (error == IRECV_E_SUCCESS) {
- return error;
+ int attempts = 10;
+ irecv_client_t recovery = NULL;
+ irecv_error_t recovery_error = IRECV_E_UNKNOWN_ERROR;
+
+ for (i = 1; i <= attempts; i++) {
+ recovery_error = irecv_open(&recovery);
+ if (recovery_error == IRECV_E_SUCCESS) {
+ break;
+ }
+
+ if (i >= attempts) {
+ error("ERROR: Unable to connect to device in recovery mode\n");
+ return -1;
}
sleep(2);
- info("Retrying connection...\n");
+ debug("Retrying connection...\n");
}
- error("ERROR: Unable to connect to recovery device.\n");
- return error;
+ if (idevicerestore_debug) {
+ irecv_set_debug(recovery, idevicerestore_debug);
+ }
+
+ irecv_event_subscribe(recovery, IRECV_PROGRESS, &recovery_progress_callback, NULL);
+ *client = recovery;
+ return 0;
}
-int recovery_send_ibec(char* ipsw, plist_t tss) {
- irecv_error_t error = 0;
- irecv_client_t client = NULL;
- char* component = "iBEC";
+int recovery_send_ibec(const char* ipsw, plist_t tss) {
+ irecv_client_t recovery = NULL;
+ const char* component = "iBEC";
+ irecv_error_t recovery_error = IRECV_E_SUCCESS;
- error = recovery_open_with_timeout(&client);
- if (error != IRECV_E_SUCCESS) {
+ if (recovery_open_with_timeout(&recovery) < 0) {
return -1;
}
- error = irecv_send_command(client, "setenv auto-boot true");
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = irecv_send_command(recovery, "setenv auto-boot true");
+ if (recovery_error != IRECV_E_SUCCESS) {
error("ERROR: Unable to set auto-boot environmental variable\n");
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- error = irecv_send_command(client, "saveenv");
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = irecv_send_command(recovery, "saveenv");
+ if (recovery_error != IRECV_E_SUCCESS) {
error("ERROR: Unable to save environmental variable\n");
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- if (recovery_send_signed_component(client, ipsw, tss, component) < 0) {
+ if (recovery_send_signed_component(recovery, ipsw, tss, "iBEC") < 0) {
error("ERROR: Unable to send %s to device.\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- error = irecv_send_command(client, "go");
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = irecv_send_command(recovery, "go");
+ if (recovery_error != IRECV_E_SUCCESS) {
error("ERROR: Unable to execute %s\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- if (client) {
- irecv_close(client);
- client = NULL;
- }
+ irecv_close(recovery);
+ recovery = NULL;
return 0;
}
-int recovery_send_applelogo(char* ipsw, plist_t tss) {
- irecv_error_t error = 0;
- irecv_client_t client = NULL;
- char* component = "AppleLogo";
+int recovery_send_applelogo(const char* ipsw, plist_t tss) {
+ irecv_client_t recovery = NULL;
+ const char* component = "applelogo";
+ irecv_error_t recovery_error = IRECV_E_SUCCESS;
info("Sending %s...\n", component);
-
- error = recovery_open_with_timeout(&client);
- if (error != IRECV_E_SUCCESS) {
+ if (recovery_open_with_timeout(&recovery) < 0) {
return -1;
}
- if (recovery_send_signed_component(client, ipsw, tss, component) < 0) {
+ if (recovery_send_signed_component(recovery, ipsw, tss, "AppleLogo") < 0) {
error("ERROR: Unable to send %s to device.\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- error = irecv_send_command(client, "setpicture 1");
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = irecv_send_command(recovery, "setpicture 1");
+ if (recovery_error != IRECV_E_SUCCESS) {
error("ERROR: Unable to set %s\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- error = irecv_send_command(client, "bgcolor 0 0 0");
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = irecv_send_command(recovery, "bgcolor 0 0 0");
+ if (recovery_error != IRECV_E_SUCCESS) {
error("ERROR: Unable to display %s\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- if (client) {
- irecv_close(client);
- client = NULL;
- }
+ irecv_close(recovery);
+ recovery = NULL;
return 0;
}
-int recovery_send_devicetree(char* ipsw, plist_t tss) {
- irecv_error_t error = 0;
- irecv_client_t client = NULL;
- char *component = "RestoreDeviceTree";
+int recovery_send_devicetree(const char* ipsw, plist_t tss) {
+ irecv_client_t recovery = NULL;
+ const char* component = "devicetree";
+ irecv_error_t recovery_error = IRECV_E_SUCCESS;
- error = recovery_open_with_timeout(&client);
- if (error != IRECV_E_SUCCESS) {
+ if (recovery_open_with_timeout(&recovery) < 0) {
return -1;
}
- if (recovery_send_signed_component(client, ipsw, tss, component) < 0) {
+ if (recovery_send_signed_component(recovery, ipsw, tss, "RestoreDeviceTree") < 0) {
error("ERROR: Unable to send %s to device.\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- error = irecv_send_command(client, "devicetree");
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = irecv_send_command(recovery, "devicetree");
+ if (recovery_error != IRECV_E_SUCCESS) {
error("ERROR: Unable to execute %s\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- if (client) {
- irecv_close(client);
- client = NULL;
- }
+ irecv_close(recovery);
+ recovery = NULL;
return 0;
}
-int recovery_send_ramdisk(char* ipsw, plist_t tss) {
- irecv_error_t error = 0;
- irecv_client_t client = NULL;
- char *component = "RestoreRamDisk";
+int recovery_send_ramdisk(const char* ipsw, plist_t tss) {
+ irecv_error_t recovery_error = IRECV_E_SUCCESS;
+ irecv_client_t recovery = NULL;
+ const char *component = "ramdisk";
- error = recovery_open_with_timeout(&client);
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = recovery_open_with_timeout(&recovery);
+ if (recovery_error != IRECV_E_SUCCESS) {
return -1;
}
- if (recovery_send_signed_component(client, ipsw, tss, component) < 0) {
+ if (recovery_send_signed_component(recovery, ipsw, tss, "RestoreRamDisk") < 0) {
error("ERROR: Unable to send %s to device.\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- error = irecv_send_command(client, "ramdisk");
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = irecv_send_command(recovery, "ramdisk");
+ if (recovery_error != IRECV_E_SUCCESS) {
error("ERROR: Unable to execute %s\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- if (client) {
- irecv_close(client);
- client = NULL;
- }
+ irecv_close(recovery);
+ recovery = NULL;
return 0;
}
-int recovery_send_kernelcache(char* ipsw, plist_t tss) {
- irecv_error_t error = 0;
- irecv_client_t client = NULL;
- char *component = "RestoreKernelCache";
+int recovery_send_kernelcache(const char* ipsw, plist_t tss) {
+ irecv_client_t recovery = NULL;
+ const char* component = "kernelcache";
+ irecv_error_t recovery_error = IRECV_E_SUCCESS;
- error = recovery_open_with_timeout(&client);
- if (error != IRECV_E_SUCCESS) {
+ if (recovery_open_with_timeout(&recovery) < 0) {
return -1;
}
- if (recovery_send_signed_component(client, ipsw, tss, component) < 0) {
+ if (recovery_send_signed_component(recovery, ipsw, tss, "RestoreKernelCache") < 0) {
error("ERROR: Unable to send %s to device.\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
return -1;
}
- error = irecv_send_command(client, "bootx");
- if (error != IRECV_E_SUCCESS) {
+ recovery_error = irecv_send_command(recovery, "bootx");
+ if (recovery_error != IRECV_E_SUCCESS) {
error("ERROR: Unable to execute %s\n", component);
- irecv_close(client);
- client = NULL;
+ irecv_close(recovery);
+ return -1;
+ }
+
+ irecv_close(recovery);
+ recovery = NULL;
+ return 0;
+}
+
+int recovery_get_ecid(uint64_t* ecid) {
+ irecv_client_t recovery = NULL;
+ irecv_error_t recovery_error = IRECV_E_SUCCESS;
+
+ if (recovery_open_with_timeout(&recovery) < 0) {
return -1;
}
- if (client) {
- irecv_close(client);
- client = NULL;
+ recovery_error = irecv_get_ecid(recovery, ecid);
+ if (recovery_error != IRECV_E_SUCCESS) {
+ irecv_close(recovery);
+ return -1;
}
+
+ irecv_close(recovery);
+ recovery = NULL;
return 0;
}
+int recovery_get_cpid(uint32_t* cpid) {
+ irecv_client_t recovery = NULL;
+ irecv_error_t recovery_error = IRECV_E_SUCCESS;
-int recovery_get_ecid(uint64_t* ecid) {
+ if (recovery_open_with_timeout(&recovery) < 0) {
+ return -1;
+ }
+
+ recovery_error = irecv_get_cpid(recovery, cpid);
+ if (recovery_error != IRECV_E_SUCCESS) {
+ irecv_close(recovery);
+ return -1;
+ }
+
+ irecv_close(recovery);
+ recovery = NULL;
+ return 0;
+}
+
+int recovery_get_bdid(uint32_t* bdid) {
+ irecv_client_t recovery = NULL;
+ irecv_error_t recovery_error = IRECV_E_SUCCESS;
+
+ if (recovery_open_with_timeout(&recovery) < 0) {
+ return -1;
+ }
+
+ recovery_error = irecv_get_bdid(recovery, bdid);
+ if (recovery_error != IRECV_E_SUCCESS) {
+ irecv_close(recovery);
+ return -1;
+ }
+
+ irecv_close(recovery);
+ recovery = NULL;
return 0;
}