summaryrefslogtreecommitdiffstats
path: root/src/recovery.c
diff options
context:
space:
mode:
authorGravatar Joshua Hill2010-07-08 23:40:26 -0400
committerGravatar Joshua Hill2010-07-08 23:40:26 -0400
commit4bc0f4d97a767d1291ac9f09780198d5680f3e3f (patch)
tree62b132e669be7319d749635a9b6d8fb842401810 /src/recovery.c
parent38c965c16625d26915b3d4998a8a7e790c834d89 (diff)
parent4090b98d9e8cdaada701ac320e20f7c8b0cf88f6 (diff)
downloadidevicerestore-4bc0f4d97a767d1291ac9f09780198d5680f3e3f.tar.gz
idevicerestore-4bc0f4d97a767d1291ac9f09780198d5680f3e3f.tar.bz2
Merge branch 'martin'
Diffstat (limited to 'src/recovery.c')
-rw-r--r--src/recovery.c398
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;
}