diff options
Diffstat (limited to 'src/recovery.c')
-rw-r--r-- | src/recovery.c | 398 |
1 files changed, 269 insertions, 129 deletions
diff --git a/src/recovery.c b/src/recovery.c index 4e2e7ad..6a38343 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -21,249 +21,389 @@ #include <stdio.h> #include <stdlib.h> -#include <stdint.h> #include <libirecovery.h> +#include <libimobiledevice/restore.h> +#include <libimobiledevice/libimobiledevice.h> #include "tss.h" #include "img3.h" +#include "common.h" +#include "restore.h" #include "recovery.h" #include "idevicerestore.h" -int recovery_send_signed_component(irecv_client_t client, 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) { - error("ERROR: Unable to get signed component: %s\n", component); - return -1; +int recovery_progress_callback(irecv_client_t client, const irecv_event_t* event) { + if (event->type == IRECV_PROGRESS) { + print_progress_bar(event->progress); } + return 0; +} - 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); - free(data); - free(path); +int recovery_client_new(struct idevicerestore_client_t* client) { + struct recovery_client_t* recovery = (struct recovery_client_t*) malloc(sizeof(struct recovery_client_t)); + if (recovery == NULL) { + error("ERROR: Out of memory\n"); return -1; } - if (data) { - free(data); - data = NULL; + client->recovery = recovery; + + if (recovery_open_with_timeout(client) < 0) { + recovery_client_free(client); + return -1; } + client->recovery = recovery; return 0; } -irecv_error_t recovery_open_with_timeout(irecv_client_t* client) { +void recovery_client_free(struct idevicerestore_client_t* client) { + if(client) { + if (client->recovery) { + if(client->recovery->client) { + irecv_close(client->recovery->client); + client->recovery->client = NULL; + } + free(client->recovery); + client->recovery = NULL; + } + } +} + +int recovery_open_with_timeout(struct idevicerestore_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; + + if(client->recovery == NULL) { + if(recovery_client_new(client) < 0) { + error("ERROR: Unable to open device in recovery mode\n"); + return -1; + } + return 0; + } + + 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; + irecv_event_subscribe(recovery, IRECV_PROGRESS, &recovery_progress_callback, NULL); + client->recovery->client = recovery; + return 0; } -int recovery_send_ibec(char* ipsw, plist_t tss) { +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(struct idevicerestore_client_t* client, plist_t build_identity) { + idevice_t device = NULL; + restored_client_t restore = NULL; + + // upload data to make device boot restore mode + if (recovery_send_ibec(client, build_identity) < 0) { + error("ERROR: Unable to send iBEC\n"); + return -1; + } + sleep(2); + + if (recovery_send_applelogo(client, build_identity) < 0) { + error("ERROR: Unable to send AppleLogo\n"); + return -1; + } + + if (recovery_send_devicetree(client, build_identity) < 0) { + error("ERROR: Unable to send DeviceTree\n"); + return -1; + } + + if (recovery_send_ramdisk(client, build_identity) < 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(); + + info("Resetting recovery mode connection...\n"); + irecv_reset(client->recovery->client); + + if (recovery_send_kernelcache(client, build_identity) < 0) { + error("ERROR: Unable to send KernelCache\n"); + return -1; + } + + info("Waiting for device to enter restore mode\n"); + if (restore_open_with_timeout(client) < 0) { + error("ERROR: Unable to connect to device in restore mode\n"); + return -1; + } + + restore_client_free(client); + client->mode = &idevicerestore_modes[MODE_RESTORE]; + return 0; +} + +int recovery_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component) { + uint32_t size = 0; + char* data = NULL; + char* path = NULL; + char* blob = NULL; irecv_error_t error = 0; - irecv_client_t client = NULL; - char* component = "iBEC"; - error = recovery_open_with_timeout(&client); - if (error != IRECV_E_SUCCESS) { + if (client->tss) { + if (tss_get_entry_path(client->tss, component, &path) < 0) { + error("ERROR: Unable to get component path\n"); + return -1; + } + } else { + if (build_identity_get_component_path(build_identity, component, &path) < 0) { + error("ERROR: Unable to get component: %s\n", component); + if (path) + free(path); + return -1; + } + } + + info("Resetting recovery mode connection...\n"); + irecv_reset(client->recovery->client); + + if (ipsw_get_component_by_path(client->ipsw, client->tss, path, &data, &size) < 0) { + error("ERROR: Unable to get component: %s\n", component); + free(path); return -1; } - error = irecv_send_command(client, "setenv auto-boot true"); + info("Sending %s (%d bytes)...\n", component, size); + + error = irecv_send_buffer(client->recovery->client, data, size); + free(path); if (error != IRECV_E_SUCCESS) { + error("ERROR: Unable to send %s component: %s\n", component, irecv_strerror(error)); + free(data); + return -1; + } + + free(data); + return 0; +} + +static int recovery_enable_autoboot(struct idevicerestore_client_t* client) { + irecv_error_t recovery_error = IRECV_E_SUCCESS; + //recovery_error = irecv_send_command(client->recovery->client, "setenv auto-boot true"); + recovery_error = irecv_setenv(client->recovery->client, "auto-boot", "true"); + if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to set auto-boot environmental variable\n"); - irecv_close(client); - client = NULL; return -1; } - error = irecv_send_command(client, "saveenv"); - if (error != IRECV_E_SUCCESS) { + recovery_error = irecv_send_command(client->recovery->client, "saveenv"); + if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to save environmental variable\n"); - irecv_close(client); - client = NULL; return -1; } - if (recovery_send_signed_component(client, ipsw, tss, component) < 0) { + return 0; +} + +int recovery_send_ibec(struct idevicerestore_client_t* client, plist_t build_identity) { + const char* component = "iBEC"; + irecv_error_t recovery_error = IRECV_E_SUCCESS; + + if (recovery_enable_autoboot(client) < 0) { + return -1; + } + + if (recovery_send_component(client, build_identity, component) < 0) { error("ERROR: Unable to send %s to device.\n", component); - irecv_close(client); - client = NULL; return -1; } - error = irecv_send_command(client, "go"); - if (error != IRECV_E_SUCCESS) { + recovery_error = irecv_send_command(client->recovery->client, "go"); + if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); - irecv_close(client); - client = NULL; return -1; } - if (client) { - irecv_close(client); - client = 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(struct idevicerestore_client_t* client, plist_t build_identity) { + 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(client) < 0) { return -1; } - if (recovery_send_signed_component(client, ipsw, tss, component) < 0) { + if (recovery_send_component(client, build_identity, component) < 0) { error("ERROR: Unable to send %s to device.\n", component); - irecv_close(client); - client = NULL; return -1; } - error = irecv_send_command(client, "setpicture 1"); - if (error != IRECV_E_SUCCESS) { + recovery_error = irecv_send_command(client->recovery->client, "setpicture 1"); + if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to set %s\n", component); - irecv_close(client); - client = NULL; return -1; } - error = irecv_send_command(client, "bgcolor 0 0 0"); - if (error != IRECV_E_SUCCESS) { + recovery_error = irecv_send_command(client->recovery->client, "bgcolor 0 0 0"); + if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to display %s\n", component); - irecv_close(client); - client = NULL; return -1; } - if (client) { - irecv_close(client); - client = 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(struct idevicerestore_client_t* client, plist_t build_identity) { + const char* component = "RestoreDeviceTree"; + irecv_error_t recovery_error = IRECV_E_SUCCESS; - error = recovery_open_with_timeout(&client); - if (error != IRECV_E_SUCCESS) { - return -1; + if(client->recovery == NULL) { + if (recovery_open_with_timeout(client) < 0) { + return -1; + } } - if (recovery_send_signed_component(client, ipsw, tss, component) < 0) { + if (recovery_send_component(client, build_identity, component) < 0) { error("ERROR: Unable to send %s to device.\n", component); - irecv_close(client); - client = NULL; return -1; } - error = irecv_send_command(client, "devicetree"); - if (error != IRECV_E_SUCCESS) { + recovery_error = irecv_send_command(client->recovery->client, "devicetree"); + if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); - irecv_close(client); - client = NULL; return -1; } - if (client) { - irecv_close(client); - client = 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(struct idevicerestore_client_t* client, plist_t build_identity) { + const char *component = "RestoreRamDisk"; + irecv_error_t recovery_error = IRECV_E_SUCCESS; - error = recovery_open_with_timeout(&client); - if (error != IRECV_E_SUCCESS) { - return -1; + if(client->recovery == NULL) { + if (recovery_open_with_timeout(client) < 0) { + return -1; + } } - if (recovery_send_signed_component(client, ipsw, tss, component) < 0) { + if (recovery_send_component(client, build_identity, component) < 0) { error("ERROR: Unable to send %s to device.\n", component); - irecv_close(client); - client = NULL; return -1; } - error = irecv_send_command(client, "ramdisk"); - if (error != IRECV_E_SUCCESS) { + recovery_error = irecv_send_command(client->recovery->client, "ramdisk"); + if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); - irecv_close(client); - client = NULL; return -1; } - if (client) { - irecv_close(client); - client = 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(struct idevicerestore_client_t* client, plist_t build_identity) { + const char* component = "RestoreKernelCache"; + irecv_error_t recovery_error = IRECV_E_SUCCESS; - error = recovery_open_with_timeout(&client); - if (error != IRECV_E_SUCCESS) { + if (recovery_open_with_timeout(client) < 0) { return -1; } - if (recovery_send_signed_component(client, ipsw, tss, component) < 0) { + if (recovery_send_component(client, build_identity, component) < 0) { error("ERROR: Unable to send %s to device.\n", component); - irecv_close(client); - client = NULL; return -1; } - error = irecv_send_command(client, "bootx"); - if (error != IRECV_E_SUCCESS) { + recovery_error = irecv_send_command(client->recovery->client, "bootx"); + if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); - irecv_close(client); - client = NULL; return -1; } - if (client) { - irecv_close(client); - client = NULL; + return 0; +} + +int recovery_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid) { + irecv_error_t recovery_error = IRECV_E_SUCCESS; + + if(client->recovery == NULL) { + if (recovery_open_with_timeout(client) < 0) { + return -1; + } } + + recovery_error = irecv_get_ecid(client->recovery->client, ecid); + if (recovery_error != IRECV_E_SUCCESS) { + return -1; + } + return 0; } +int recovery_get_cpid(struct idevicerestore_client_t* client, uint32_t* cpid) { + irecv_error_t recovery_error = IRECV_E_SUCCESS; + + if(client->recovery == NULL) { + if (recovery_open_with_timeout(client) < 0) { + return -1; + } + } + + recovery_error = irecv_get_cpid(client->recovery->client, cpid); + if (recovery_error != IRECV_E_SUCCESS) { + return -1; + } + + return 0; +} + +int recovery_get_bdid(struct idevicerestore_client_t* client, uint32_t* bdid) { + irecv_error_t recovery_error = IRECV_E_SUCCESS; + + if(client->recovery == NULL) { + if (recovery_open_with_timeout(client) < 0) { + return -1; + } + } + + recovery_error = irecv_get_bdid(client->recovery->client, bdid); + if (recovery_error != IRECV_E_SUCCESS) { + return -1; + } -int recovery_get_ecid(uint64_t* ecid) { return 0; } |