summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Joshua Hill2010-06-01 04:34:40 -0400
committerGravatar Joshua Hill2010-06-01 04:34:40 -0400
commit4de6d38c54d9f641006539a06083e423a5d0c9c9 (patch)
tree990a89f501eaee4427ea8104a0bcf0dab438b05b /src
parent75a3f5f5c6ec5b89659f4e4aacd5d629a3912f22 (diff)
downloadidevicerestore-4de6d38c54d9f641006539a06083e423a5d0c9c9.tar.gz
idevicerestore-4de6d38c54d9f641006539a06083e423a5d0c9c9.tar.bz2
Began refactoring of code to simplify and seperate device state logic
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/dfu.c28
-rw-r--r--src/dfu.h29
-rw-r--r--src/idevicerestore.c623
-rw-r--r--src/normal.c28
-rw-r--r--src/normal.h29
-rw-r--r--src/recovery.c269
-rw-r--r--src/recovery.h37
-rw-r--r--src/restore.c405
-rw-r--r--src/restore.h36
10 files changed, 871 insertions, 615 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 540b262..6840a0c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,6 +18,6 @@ AM_LDFLAGS =\
bin_PROGRAMS = idevicerestore
-idevicerestore_SOURCES = idevicerestore.c img3.c ipsw.c tss.c
+idevicerestore_SOURCES = idevicerestore.c dfu.c tss.c img3.c ipsw.c normal.c restore.c recovery.c
idevicerestore_CFLAGS = $(AM_CFLAGS)
idevicerestore_LDFLAGS = $(AM_LDFLAGS) \ No newline at end of file
diff --git a/src/dfu.c b/src/dfu.c
new file mode 100644
index 0000000..5e13f38
--- /dev/null
+++ b/src/dfu.c
@@ -0,0 +1,28 @@
+/*
+ * dfu.c
+ * Functions for handling idevices in DFU mode
+ *
+ * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdint.h>
+
+#include "dfu.h"
+
+int dfu_get_ecid(uint64_t* ecid) {
+ return 0;
+}
diff --git a/src/dfu.h b/src/dfu.h
new file mode 100644
index 0000000..ef9d911
--- /dev/null
+++ b/src/dfu.h
@@ -0,0 +1,29 @@
+/*
+ * dfu.h
+ * Functions for handling idevices in normal mode
+ *
+ * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef DFU_H
+#define DFU_H
+
+#include <stdint.h>
+
+int dfu_get_ecid(uint64_t* ecid);
+
+#endif
diff --git a/src/idevicerestore.c b/src/idevicerestore.c
index fa685bd..aaff4d6 100644
--- a/src/idevicerestore.c
+++ b/src/idevicerestore.c
@@ -29,17 +29,20 @@
#include <libimobiledevice/lockdown.h>
#include <libimobiledevice/libimobiledevice.h>
+#include "dfu.h"
#include "tss.h"
#include "img3.h"
#include "ipsw.h"
+#include "normal.h"
+#include "restore.h"
+#include "recovery.h"
#include "idevicerestore.h"
#define UNKNOWN_MODE 0
-#define NORMAL_MODE 1
-#define RECOVERY_MODE 2
-#define RESTORE_MODE 3
-
-#define ASR_PORT 12345
+#define DFU_MODE 1
+#define NORMAL_MODE 2
+#define RECOVERY_MODE 3
+#define RESTORE_MODE 4
int idevicerestore_debug = 0;
static int idevicerestore_mode = 0;
@@ -48,11 +51,6 @@ static int idevicerestore_custom = 0;
void usage(int argc, char* argv[]);
int write_file(const char* filename, char* data, int size);
-int recovery_send_ibec(char* ipsw, plist_t tss);
-int recovery_send_applelogo(char* ipsw, plist_t tss);
-int recovery_send_devicetree(char* ipsw, plist_t tss);
-int recovery_send_ramdisk(char* ipsw, plist_t tss);
-int recovery_send_kernelcache(char* ipsw, plist_t tss);
int get_tss_data_by_name(plist_t tss, const char* entry, char** path, char** blob);
int get_tss_data_by_path(plist_t tss, const char* path, char** name, char** blob);
void device_callback(const idevice_event_t* event, void *user_data);
@@ -379,7 +377,7 @@ int main(int argc, char* argv[]) {
free(kernelcache_data);
} else if (!strcmp(datatype, "NORData")) {
- send_nor_data(restore, ipsw, tss_response);
+ restore_send_nor_data(restore, ipsw, tss_response);
} else {
// Unknown DataType!!
@@ -435,375 +433,6 @@ void usage(int argc, char* argv[]) {
exit(1);
}
-int restore_handle_progress_msg(restored_client_t client, plist_t msg) {
- const char operation_name[][35] = {
- "Unknown 1",
- "Unknown 2",
- "Unknown 3",
- "Unknown 4",
- "Unknown 5",
- "Unknown 6",
- "Unknown 7",
- "Unknown 8",
- "Unknown 9",
- "Unknown 10",
- "Unknown 11",
- "Creating partition map",
- "Creating filesystem",
- "Restoring image",
- "Verifying restore",
- "Checking filesystems",
- "Mounting filesystems",
- "Unknown 18",
- "Flashing NOR",
- "Updating baseband",
- "Finalizing NAND epoch update",
- "Unknown 22",
- "Unknown 23",
- "Unknown 24",
- "Unknown 25",
- "Modifying persistent boot-args",
- "Unknown 27",
- "Unknown 28",
- "Waiting for NAND",
- "Unmounting filesystems",
- "Unknown 31",
- "Unknown 32",
- "Waiting for Device...",
- "Unknown 34",
- "Unknown 35",
- "Loading NOR data to flash"
- };
-
- plist_t node = NULL;
- uint64_t operation = 0;
- uint64_t uprogress = 0;
- int progress = 0;
-
- node = plist_dict_get_item(msg, "Operation");
- if (node && PLIST_UINT == plist_get_node_type(node)) {
- plist_get_uint_val(node, &operation);
- } else {
- debug("Failed to parse operation from ProgressMsg plist\n");
- return 0;
- }
-
- node = plist_dict_get_item(msg, "Progress");
- if (node && PLIST_UINT == plist_get_node_type(node)) {
- plist_get_uint_val(node, &uprogress);
- progress = (int) uprogress;
- } else {
- debug("Failed to parse progress from ProgressMsg plist \n");
- return 0;
- }
-
- if ((progress > 0) && (progress < 100))
- info("%s - Progress: %llu%\n", operation_name[operation], progress);
- else
- info("%s\n", operation_name[operation]);
-
- return 0;
-}
-
-int restore_handle_data_request_msg(idevice_t device, restored_client_t client, plist_t msg, const char *filesystem, const char *kernel) {
- plist_t datatype_node = plist_dict_get_item(msg, "DataType");
- if (datatype_node && PLIST_STRING == plist_get_node_type(datatype_node)) {
- char *datatype = NULL;
- plist_get_string_val(datatype_node, &datatype);
- if (!strcmp(datatype, "SystemImageData")) {
- asr_send_system_image_data_from_file(device, client, filesystem);
- } else if (!strcmp(datatype, "KernelCache")) {
- restore_send_kernelcache(client, kernel);
- } else if (!strcmp(datatype, "NORData")) {
- send_nor_data(device, client);
- } else {
- // Unknown DataType!!
- error("Unknown DataType\n");
- return -1;
- }
- }
- return 0;
-}
-
-int restore_handle_status_msg(restored_client_t client, plist_t msg) {
- info("Got status message\n");
- return 0;
-}
-
-int asr_send_system_image_data_from_file(idevice_t device, restored_client_t client, const char *filesystem) {
- int i = 0;
- char buffer[0x1000];
- uint32_t recv_bytes = 0;
- memset(buffer, '\0', 0x1000);
- idevice_connection_t connection = NULL;
- idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
-
- for (i = 0; i < 5; i++) {
- ret = idevice_connect(device, ASR_PORT, &connection);
- if (ret == IDEVICE_E_SUCCESS)
- break;
-
- else
- sleep(1);
- }
-
- if (ret != IDEVICE_E_SUCCESS)
- return ret;
-
- memset(buffer, '\0', 0x1000);
- ret = idevice_connection_receive(connection, buffer, 0x1000, &recv_bytes);
- if (ret != IDEVICE_E_SUCCESS) {
- idevice_disconnect(connection);
- return ret;
- }
- info("Received %d bytes\n", recv_bytes);
- info("%s", buffer);
-
- FILE* fd = fopen(filesystem, "rb");
- if (fd == NULL) {
- idevice_disconnect(connection);
- return ret;
- }
-
- fseek(fd, 0, SEEK_END);
- uint64_t len = ftell(fd);
- fseek(fd, 0, SEEK_SET);
-
- info("Connected to ASR\n");
- plist_t dict = plist_new_dict();
- plist_dict_insert_item(dict, "FEC Slice Stride", plist_new_uint(40));
- plist_dict_insert_item(dict, "Packet Payload Size", plist_new_uint(1450));
- plist_dict_insert_item(dict, "Packets Per FEC", plist_new_uint(25));
-
- plist_t payload = plist_new_dict();
- plist_dict_insert_item(payload, "Port", plist_new_uint(1));
- plist_dict_insert_item(payload, "Size", plist_new_uint(len));
- plist_dict_insert_item(dict, "Payload", payload);
-
- plist_dict_insert_item(dict, "Stream ID", plist_new_uint(1));
- plist_dict_insert_item(dict, "Version", plist_new_uint(1));
-
- char* xml = NULL;
- unsigned int dict_size = 0;
- unsigned int sent_bytes = 0;
- plist_to_xml(dict, &xml, &dict_size);
-
- ret = idevice_connection_send(connection, xml, dict_size, &sent_bytes);
- if (ret != IDEVICE_E_SUCCESS) {
- idevice_disconnect(connection);
- return ret;
- }
-
- info("Sent %d bytes\n", sent_bytes);
- info("%s", xml);
- plist_free(dict);
- free(xml);
-
- char* command = NULL;
- do {
- memset(buffer, '\0', 0x1000);
- ret = idevice_connection_receive(connection, buffer, 0x1000, &recv_bytes);
- if (ret != IDEVICE_E_SUCCESS) {
- idevice_disconnect(connection);
- return ret;
- }
- info("Received %d bytes\n", recv_bytes);
- info("%s", buffer);
-
- plist_t request = NULL;
- plist_from_xml(buffer, recv_bytes, &request);
- plist_t command_node = plist_dict_get_item(request, "Command");
- if (command_node && PLIST_STRING == plist_get_node_type(command_node)) {
- plist_get_string_val(command_node, &command);
- if (!strcmp(command, "OOBData")) {
- plist_t oob_length_node = plist_dict_get_item(request, "OOB Length");
- if (!oob_length_node || PLIST_UINT != plist_get_node_type(oob_length_node)) {
- error("Error fetching OOB Length\n");
- idevice_disconnect(connection);
- return IDEVICE_E_UNKNOWN_ERROR;
- }
- uint64_t oob_length = 0;
- plist_get_uint_val(oob_length_node, &oob_length);
-
- plist_t oob_offset_node = plist_dict_get_item(request, "OOB Offset");
- if (!oob_offset_node || PLIST_UINT != plist_get_node_type(oob_offset_node)) {
- error("Error fetching OOB Offset\n");
- idevice_disconnect(connection);
- return IDEVICE_E_UNKNOWN_ERROR;
- }
- uint64_t oob_offset = 0;
- plist_get_uint_val(oob_offset_node, &oob_offset);
-
- char* oob_data = (char*) malloc(oob_length);
- if (oob_data == NULL) {
- error("Out of memory\n");
- idevice_disconnect(connection);
- return IDEVICE_E_UNKNOWN_ERROR;
- }
-
- fseek(fd, oob_offset, SEEK_SET);
- if (fread(oob_data, 1, oob_length, fd) != oob_length) {
- error("Unable to read filesystem offset\n");
- idevice_disconnect(connection);
- free(oob_data);
- return ret;
- }
-
- ret = idevice_connection_send(connection, oob_data, oob_length, &sent_bytes);
- if (sent_bytes != oob_length || ret != IDEVICE_E_SUCCESS) {
- error("Unable to send %d bytes to asr\n", sent_bytes);
- idevice_disconnect(connection);
- free(oob_data);
- return ret;
- }
- plist_free(request);
- free(oob_data);
- }
- }
-
- } while (strcmp(command, "Payload"));
-
- fseek(fd, 0, SEEK_SET);
- char data[1450];
- for (i = len; i > 0; i -= 1450) {
- int size = 1450;
- if (i < 1450) {
- size = i;
- }
-
- if (fread(data, 1, size, fd) != (unsigned int) size) {
- fclose(fd);
- idevice_disconnect(connection);
- error("Error reading filesystem\n");
- return IDEVICE_E_UNKNOWN_ERROR;
- }
-
- ret = idevice_connection_send(connection, data, size, &sent_bytes);
- if (ret != IDEVICE_E_SUCCESS) {
- fclose(fd);
- }
-
- if (i % (1450 * 1000) == 0) {
- info(".");
- }
- }
-
- info("Done sending filesystem\n");
- fclose(fd);
- ret = idevice_disconnect(connection);
- return ret;
-}
-
-int restore_send_kernelcache(restored_client_t client, char *kernel_data, int len) {
- info("Sending kernelcache\n");
-
- plist_t kernelcache_node = plist_new_data(kernel_data, len);
-
- plist_t dict = plist_new_dict();
- plist_dict_insert_item(dict, "KernelCacheFile", kernelcache_node);
-
- restored_error_t ret = restored_send(client, dict);
- if (ret != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to send kernelcache data\n");
- plist_free(dict);
- return -1;
- }
-
- info("Done sending kernelcache\n");
- plist_free(dict);
- return 0;
-}
-
-int send_nor_data(restored_client_t client, char* ipsw, plist_t tss) {
- char* llb_path = NULL;
- char* llb_blob = NULL;
- if (get_tss_data_by_name(tss, "LLB", &llb_path, &llb_blob) < 0) {
- error("ERROR: Unable to get LLB info from TSS response\n");
- return -1;
- }
-
- char* llb_filename = strstr(llb_path, "LLB");
- if (llb_filename == NULL) {
- error("ERROR: Unable to extrac firmware path from LLB filename\n");
- free(llb_path);
- free(llb_blob);
- return -1;
- }
-
- char firmware_path[256];
- memset(firmware_path, '\0', sizeof(firmware_path));
- memcpy(firmware_path, llb_path, (llb_filename - 1) - llb_path);
- info("Found firmware path %s\n", firmware_path);
-
- char manifest_file[256];
- memset(manifest_file, '\0', sizeof(manifest_file));
- snprintf(manifest_file, sizeof(manifest_file), "%s/manifest", firmware_path);
- info("Getting firmware manifest %s\n", manifest_file);
-
- int manifest_size = 0;
- char* manifest_data = NULL;
- if (ipsw_extract_to_memory(ipsw, manifest_file, &manifest_data, &manifest_size) < 0) {
- error("ERROR: Unable to extract firmware manifest from ipsw\n");
- free(llb_path);
- free(llb_blob);
- return -1;
- }
-
- char firmware_filename[256];
- memset(firmware_filename, '\0', sizeof(firmware_filename));
-
- int llb_size = 0;
- char* llb_data = NULL;
- plist_t dict = plist_new_dict();
- char* filename = strtok(manifest_data, "\n");
- if (filename != NULL) {
- memset(firmware_filename, '\0', sizeof(firmware_filename));
- snprintf(firmware_filename, sizeof(firmware_filename), "%s/%s", firmware_path, filename);
- if (get_signed_component_by_path(ipsw, tss, firmware_filename, &llb_data, &llb_size) < 0) {
- error("ERROR: Unable to get signed LLB\n");
- return -1;
- }
-
- plist_dict_insert_item(dict, "LlbImageData", plist_new_data(llb_data, (uint64_t) llb_size));
- }
-
- int nor_size = 0;
- char* nor_data = NULL;
- filename = strtok(NULL, "\n");
- plist_t norimage_array = plist_new_array();
- while (filename != NULL) {
- memset(firmware_filename, '\0', sizeof(firmware_filename));
- snprintf(firmware_filename, sizeof(firmware_filename), "%s/%s", firmware_path, filename);
- if (get_signed_component_by_path(ipsw, tss, firmware_filename, &nor_data, &nor_size) < 0) {
- error("ERROR: Unable to get signed firmware %s\n", firmware_filename);
- break;
- }
-
- plist_array_append_item(norimage_array, plist_new_data(nor_data, (uint64_t) nor_size));
- free(nor_data);
- nor_data = NULL;
- nor_size = 0;
- filename = strtok(NULL, "\n");
- }
- plist_dict_insert_item(dict, "NorImageData", norimage_array);
-
- int sz = 0;
- char* xml = NULL;
- plist_to_xml(dict, &xml, &sz);
- debug("%s", xml);
- free(xml);
-
- restored_error_t ret = restored_send(client, dict);
- if (ret != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to send kernelcache data\n");
- plist_free(dict);
- return -1;
- }
-
- plist_free(dict);
- return 0;
-}
-
int write_file(const char* filename, char* data, int size) {
debug("Writing data to %s\n", filename);
FILE* file = fopen(filename, "wb");
@@ -1058,237 +687,3 @@ int get_signed_component_by_path(char* ipsw, plist_t tss, char* path, char** pda
*psize = size;
return 0;
}
-
-static 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;
- }
-
- 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);
- return -1;
- }
-
- if (data) {
- free(data);
- data = NULL;
- }
-
- return 0;
-}
-
-static irecv_error_t 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;
- }
-
- sleep(2);
- info("Retrying connection...\n");
- }
-
- error("ERROR: Unable to connect to recovery device.\n");
- return error;
-}
-
-int recovery_send_ibec(char* ipsw, plist_t tss) {
- irecv_error_t error = 0;
- irecv_client_t client = NULL;
- char* component = "iBEC";
-
- error = recovery_open_with_timeout(&client);
- if (error != IRECV_E_SUCCESS) {
- return -1;
- }
-
- error = irecv_send_command(client, "setenv auto-boot true");
- if (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) {
- 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) {
- 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) {
- 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";
-
- info("Sending %s...\n", component);
-
- error = recovery_open_with_timeout(&client);
- if (error != IRECV_E_SUCCESS) {
- return -1;
- }
-
- if (recovery_send_signed_component(client, ipsw, tss, 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) {
- 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) {
- 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";
-
- error = recovery_open_with_timeout(&client);
- if (error != IRECV_E_SUCCESS) {
- return -1;
- }
-
- if (recovery_send_signed_component(client, ipsw, tss, 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) {
- 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";
-
- error = recovery_open_with_timeout(&client);
- if (error != IRECV_E_SUCCESS) {
- return -1;
- }
-
- if (recovery_send_signed_component(client, ipsw, tss, 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) {
- 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";
-
- error = recovery_open_with_timeout(&client);
- if (error != IRECV_E_SUCCESS) {
- return -1;
- }
-
- if (recovery_send_signed_component(client, ipsw, tss, 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) {
- error("ERROR: Unable to execute %s\n", component);
- irecv_close(client);
- client = NULL;
- return -1;
- }
-
- if (client) {
- irecv_close(client);
- client = NULL;
- }
- return 0;
-}
diff --git a/src/normal.c b/src/normal.c
new file mode 100644
index 0000000..c7baefd
--- /dev/null
+++ b/src/normal.c
@@ -0,0 +1,28 @@
+/*
+ * normal.h
+ * Functions for handling idevices in normal mode
+ *
+ * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdint.h>
+
+#include "normal.h"
+
+int normal_get_ecid(uint64_t* ecid) {
+ return 0;
+}
diff --git a/src/normal.h b/src/normal.h
new file mode 100644
index 0000000..3e2868d
--- /dev/null
+++ b/src/normal.h
@@ -0,0 +1,29 @@
+/*
+ * normal.h
+ * Functions for handling idevices in normal mode
+ *
+ * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef NORMAL_H
+#define NORMAL_H
+
+#include <stdint.h>
+
+int normal_get_ecid(uint64_t* ecid);
+
+#endif
diff --git a/src/recovery.c b/src/recovery.c
new file mode 100644
index 0000000..4e2e7ad
--- /dev/null
+++ b/src/recovery.c
@@ -0,0 +1,269 @@
+/*
+ * recovery.c
+ * Functions for handling idevices in recovery mode
+ *
+ * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <libirecovery.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 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;
+ }
+
+ 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);
+ return -1;
+ }
+
+ if (data) {
+ free(data);
+ data = NULL;
+ }
+
+ return 0;
+}
+
+irecv_error_t 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;
+ }
+
+ sleep(2);
+ info("Retrying connection...\n");
+ }
+
+ error("ERROR: Unable to connect to recovery device.\n");
+ return error;
+}
+
+int recovery_send_ibec(char* ipsw, plist_t tss) {
+ irecv_error_t error = 0;
+ irecv_client_t client = NULL;
+ char* component = "iBEC";
+
+ error = recovery_open_with_timeout(&client);
+ if (error != IRECV_E_SUCCESS) {
+ return -1;
+ }
+
+ error = irecv_send_command(client, "setenv auto-boot true");
+ if (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) {
+ 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) {
+ 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) {
+ 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";
+
+ info("Sending %s...\n", component);
+
+ error = recovery_open_with_timeout(&client);
+ if (error != IRECV_E_SUCCESS) {
+ return -1;
+ }
+
+ if (recovery_send_signed_component(client, ipsw, tss, 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) {
+ 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) {
+ 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";
+
+ error = recovery_open_with_timeout(&client);
+ if (error != IRECV_E_SUCCESS) {
+ return -1;
+ }
+
+ if (recovery_send_signed_component(client, ipsw, tss, 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) {
+ 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";
+
+ error = recovery_open_with_timeout(&client);
+ if (error != IRECV_E_SUCCESS) {
+ return -1;
+ }
+
+ if (recovery_send_signed_component(client, ipsw, tss, 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) {
+ 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";
+
+ error = recovery_open_with_timeout(&client);
+ if (error != IRECV_E_SUCCESS) {
+ return -1;
+ }
+
+ if (recovery_send_signed_component(client, ipsw, tss, 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) {
+ 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(uint64_t* ecid) {
+ return 0;
+}
diff --git a/src/recovery.h b/src/recovery.h
new file mode 100644
index 0000000..5495638
--- /dev/null
+++ b/src/recovery.h
@@ -0,0 +1,37 @@
+/*
+ * recovery.h
+ * Functions for handling idevices in recovery mode
+ *
+ * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef RECOVERY_H
+#define RECOVERY_H
+
+#include <stdint.h>
+#include <plist/plist.h>
+
+int recovery_send_signed_component(irecv_client_t client, char* ipsw, plist_t tss, char* component);
+irecv_error_t recovery_open_with_timeout(irecv_client_t* client);
+int recovery_send_ibec(char* ipsw, plist_t tss);
+int recovery_send_applelogo(char* ipsw, plist_t tss);
+int recovery_send_devicetree(char* ipsw, plist_t tss);
+int recovery_send_ramdisk(char* ipsw, plist_t tss);
+int recovery_send_kernelcache(char* ipsw, plist_t tss);
+int recovery_get_ecid(uint64_t* ecid);
+
+#endif
diff --git a/src/restore.c b/src/restore.c
new file mode 100644
index 0000000..485df9b
--- /dev/null
+++ b/src/restore.c
@@ -0,0 +1,405 @@
+/*
+ * restore.c
+ * Functions for handling idevices in restore mode
+ *
+ * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libimobiledevice/restore.h>
+
+#include "restore.h"
+#include "idevicerestore.h"
+
+#define ASR_PORT 12345
+
+#define CREATE_PARTITION_MAP 12
+#define CREATE_FILESYSTEM 13
+#define RESTORE_IMAGE 14
+#define VERIFY_RESTORE 15
+#define CHECK_FILESYSTEM 16
+#define MOUNT_FILESYSTEM 17
+#define FLASH_NOR 19
+#define UPDATE_BASEBAND 20
+#define FINIALIZE_NAND 21
+#define MODIFY_BOOTARGS 26
+#define WAIT_FOR_NAND 29
+#define UNMOUNT_FILESYSTEM 30
+#define WAIT_FOR_DEVICE 33
+#define LOAD_NOR 36
+
+const char* restore_progress_string(unsigned int operation) {
+ switch(operation) {
+ case CREATE_PARTITION_MAP:
+ return "Creating partition map";
+
+ case CREATE_FILESYSTEM:
+ return "Creating filesystem";
+
+ case RESTORE_IMAGE:
+ return "Restoring image";
+
+ case VERIFY_RESTORE:
+ return "Verifying restore";
+
+ case CHECK_FILESYSTEM:
+ return "Checking filesystems";
+
+ case MOUNT_FILESYSTEM:
+ return "Mounting filesystems";
+
+ case FLASH_NOR:
+ return "Flashing NOR";
+
+ case UPDATE_BASEBAND:
+ return "Updating baseband";
+
+ case FINIALIZE_NAND:
+ return "Finalizing NAND epoch update";
+
+ case MODIFY_BOOTARGS:
+ return "Modifying persistent boot-args";
+
+ case UNMOUNT_FILESYSTEM:
+ return "Unmounting filesystems";
+
+ case WAIT_FOR_NAND:
+ return "Waiting for NAND...";
+
+ case WAIT_FOR_DEVICE:
+ return "Waiting for Device...";
+
+ case LOAD_NOR:
+ return "Loading NOR data to flash";
+
+ default:
+ return "Unknown operation";
+ }
+}
+
+
+int restore_handle_progress_msg(restored_client_t client, plist_t msg) {
+ plist_t node = NULL;
+ uint64_t operation = 0;
+ uint64_t uprogress = 0;
+ uint32_t progress = 0;
+
+ node = plist_dict_get_item(msg, "Operation");
+ if (node && PLIST_UINT == plist_get_node_type(node)) {
+ plist_get_uint_val(node, &operation);
+ } else {
+ debug("Failed to parse operation from ProgressMsg plist\n");
+ return 0;
+ }
+
+ node = plist_dict_get_item(msg, "Progress");
+ if (node && PLIST_UINT == plist_get_node_type(node)) {
+ plist_get_uint_val(node, &uprogress);
+ progress = (uint32_t) uprogress;
+ } else {
+ debug("Failed to parse progress from ProgressMsg plist \n");
+ return 0;
+ }
+
+ if ((progress > 0) && (progress < 100))
+ info("%s - Progress: %ul%%\n", restore_progress_string(operation), progress);
+ else
+ info("%s\n", restore_progress_string(operation));
+
+ return 0;
+}
+
+int restore_handle_status_msg(restored_client_t client, plist_t msg) {
+ info("Got status message\n");
+ return 0;
+}
+
+int asr_send_system_image_data_from_file(idevice_t device, restored_client_t client, const char *filesystem) {
+ int i = 0;
+ char buffer[0x1000];
+ uint32_t recv_bytes = 0;
+ memset(buffer, '\0', 0x1000);
+ idevice_connection_t connection = NULL;
+ idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
+
+ for (i = 0; i < 5; i++) {
+ ret = idevice_connect(device, ASR_PORT, &connection);
+ if (ret == IDEVICE_E_SUCCESS)
+ break;
+
+ else
+ sleep(1);
+ }
+
+ if (ret != IDEVICE_E_SUCCESS)
+ return ret;
+
+ memset(buffer, '\0', 0x1000);
+ ret = idevice_connection_receive(connection, buffer, 0x1000, &recv_bytes);
+ if (ret != IDEVICE_E_SUCCESS) {
+ idevice_disconnect(connection);
+ return ret;
+ }
+ info("Received %d bytes\n", recv_bytes);
+ info("%s", buffer);
+
+ FILE* fd = fopen(filesystem, "rb");
+ if (fd == NULL) {
+ idevice_disconnect(connection);
+ return ret;
+ }
+
+ fseek(fd, 0, SEEK_END);
+ uint64_t len = ftell(fd);
+ fseek(fd, 0, SEEK_SET);
+
+ info("Connected to ASR\n");
+ plist_t dict = plist_new_dict();
+ plist_dict_insert_item(dict, "FEC Slice Stride", plist_new_uint(40));
+ plist_dict_insert_item(dict, "Packet Payload Size", plist_new_uint(1450));
+ plist_dict_insert_item(dict, "Packets Per FEC", plist_new_uint(25));
+
+ plist_t payload = plist_new_dict();
+ plist_dict_insert_item(payload, "Port", plist_new_uint(1));
+ plist_dict_insert_item(payload, "Size", plist_new_uint(len));
+ plist_dict_insert_item(dict, "Payload", payload);
+
+ plist_dict_insert_item(dict, "Stream ID", plist_new_uint(1));
+ plist_dict_insert_item(dict, "Version", plist_new_uint(1));
+
+ char* xml = NULL;
+ unsigned int dict_size = 0;
+ unsigned int sent_bytes = 0;
+ plist_to_xml(dict, &xml, &dict_size);
+
+ ret = idevice_connection_send(connection, xml, dict_size, &sent_bytes);
+ if (ret != IDEVICE_E_SUCCESS) {
+ idevice_disconnect(connection);
+ return ret;
+ }
+
+ info("Sent %d bytes\n", sent_bytes);
+ info("%s", xml);
+ plist_free(dict);
+ free(xml);
+
+ char* command = NULL;
+ do {
+ memset(buffer, '\0', 0x1000);
+ ret = idevice_connection_receive(connection, buffer, 0x1000, &recv_bytes);
+ if (ret != IDEVICE_E_SUCCESS) {
+ idevice_disconnect(connection);
+ return ret;
+ }
+ info("Received %d bytes\n", recv_bytes);
+ info("%s", buffer);
+
+ plist_t request = NULL;
+ plist_from_xml(buffer, recv_bytes, &request);
+ plist_t command_node = plist_dict_get_item(request, "Command");
+ if (command_node && PLIST_STRING == plist_get_node_type(command_node)) {
+ plist_get_string_val(command_node, &command);
+ if (!strcmp(command, "OOBData")) {
+ plist_t oob_length_node = plist_dict_get_item(request, "OOB Length");
+ if (!oob_length_node || PLIST_UINT != plist_get_node_type(oob_length_node)) {
+ error("Error fetching OOB Length\n");
+ idevice_disconnect(connection);
+ return IDEVICE_E_UNKNOWN_ERROR;
+ }
+ uint64_t oob_length = 0;
+ plist_get_uint_val(oob_length_node, &oob_length);
+
+ plist_t oob_offset_node = plist_dict_get_item(request, "OOB Offset");
+ if (!oob_offset_node || PLIST_UINT != plist_get_node_type(oob_offset_node)) {
+ error("Error fetching OOB Offset\n");
+ idevice_disconnect(connection);
+ return IDEVICE_E_UNKNOWN_ERROR;
+ }
+ uint64_t oob_offset = 0;
+ plist_get_uint_val(oob_offset_node, &oob_offset);
+
+ char* oob_data = (char*) malloc(oob_length);
+ if (oob_data == NULL) {
+ error("Out of memory\n");
+ idevice_disconnect(connection);
+ return IDEVICE_E_UNKNOWN_ERROR;
+ }
+
+ fseek(fd, oob_offset, SEEK_SET);
+ if (fread(oob_data, 1, oob_length, fd) != oob_length) {
+ error("Unable to read filesystem offset\n");
+ idevice_disconnect(connection);
+ free(oob_data);
+ return ret;
+ }
+
+ ret = idevice_connection_send(connection, oob_data, oob_length, &sent_bytes);
+ if (sent_bytes != oob_length || ret != IDEVICE_E_SUCCESS) {
+ error("Unable to send %d bytes to asr\n", sent_bytes);
+ idevice_disconnect(connection);
+ free(oob_data);
+ return ret;
+ }
+ plist_free(request);
+ free(oob_data);
+ }
+ }
+
+ } while (strcmp(command, "Payload"));
+
+ fseek(fd, 0, SEEK_SET);
+ char data[1450];
+ for (i = len; i > 0; i -= 1450) {
+ int size = 1450;
+ if (i < 1450) {
+ size = i;
+ }
+
+ if (fread(data, 1, size, fd) != (unsigned int) size) {
+ fclose(fd);
+ idevice_disconnect(connection);
+ error("Error reading filesystem\n");
+ return IDEVICE_E_UNKNOWN_ERROR;
+ }
+
+ ret = idevice_connection_send(connection, data, size, &sent_bytes);
+ if (ret != IDEVICE_E_SUCCESS) {
+ fclose(fd);
+ }
+
+ if (i % (1450 * 1000) == 0) {
+ info(".");
+ }
+ }
+
+ info("Done sending filesystem\n");
+ fclose(fd);
+ ret = idevice_disconnect(connection);
+ return ret;
+}
+
+int restore_send_kernelcache(restored_client_t client, char *kernel_data, int len) {
+ info("Sending kernelcache\n");
+
+ plist_t kernelcache_node = plist_new_data(kernel_data, len);
+
+ plist_t dict = plist_new_dict();
+ plist_dict_insert_item(dict, "KernelCacheFile", kernelcache_node);
+
+ restored_error_t ret = restored_send(client, dict);
+ if (ret != RESTORE_E_SUCCESS) {
+ error("ERROR: Unable to send kernelcache data\n");
+ plist_free(dict);
+ return -1;
+ }
+
+ info("Done sending kernelcache\n");
+ plist_free(dict);
+ return 0;
+}
+
+int restore_send_nor_data(restored_client_t client, char* ipsw, plist_t tss) {
+ char* llb_path = NULL;
+ char* llb_blob = NULL;
+ if (get_tss_data_by_name(tss, "LLB", &llb_path, &llb_blob) < 0) {
+ error("ERROR: Unable to get LLB info from TSS response\n");
+ return -1;
+ }
+
+ char* llb_filename = strstr(llb_path, "LLB");
+ if (llb_filename == NULL) {
+ error("ERROR: Unable to extrac firmware path from LLB filename\n");
+ free(llb_path);
+ free(llb_blob);
+ return -1;
+ }
+
+ char firmware_path[256];
+ memset(firmware_path, '\0', sizeof(firmware_path));
+ memcpy(firmware_path, llb_path, (llb_filename - 1) - llb_path);
+ info("Found firmware path %s\n", firmware_path);
+
+ char manifest_file[256];
+ memset(manifest_file, '\0', sizeof(manifest_file));
+ snprintf(manifest_file, sizeof(manifest_file), "%s/manifest", firmware_path);
+ info("Getting firmware manifest %s\n", manifest_file);
+
+ int manifest_size = 0;
+ char* manifest_data = NULL;
+ if (ipsw_extract_to_memory(ipsw, manifest_file, &manifest_data, &manifest_size) < 0) {
+ error("ERROR: Unable to extract firmware manifest from ipsw\n");
+ free(llb_path);
+ free(llb_blob);
+ return -1;
+ }
+
+ char firmware_filename[256];
+ memset(firmware_filename, '\0', sizeof(firmware_filename));
+
+ int llb_size = 0;
+ char* llb_data = NULL;
+ plist_t dict = plist_new_dict();
+ char* filename = strtok(manifest_data, "\n");
+ if (filename != NULL) {
+ memset(firmware_filename, '\0', sizeof(firmware_filename));
+ snprintf(firmware_filename, sizeof(firmware_filename), "%s/%s", firmware_path, filename);
+ if (get_signed_component_by_path(ipsw, tss, firmware_filename, &llb_data, &llb_size) < 0) {
+ error("ERROR: Unable to get signed LLB\n");
+ return -1;
+ }
+
+ plist_dict_insert_item(dict, "LlbImageData", plist_new_data(llb_data, (uint64_t) llb_size));
+ }
+
+ int nor_size = 0;
+ char* nor_data = NULL;
+ filename = strtok(NULL, "\n");
+ plist_t norimage_array = plist_new_array();
+ while (filename != NULL) {
+ memset(firmware_filename, '\0', sizeof(firmware_filename));
+ snprintf(firmware_filename, sizeof(firmware_filename), "%s/%s", firmware_path, filename);
+ if (get_signed_component_by_path(ipsw, tss, firmware_filename, &nor_data, &nor_size) < 0) {
+ error("ERROR: Unable to get signed firmware %s\n", firmware_filename);
+ break;
+ }
+
+ plist_array_append_item(norimage_array, plist_new_data(nor_data, (uint64_t) nor_size));
+ free(nor_data);
+ nor_data = NULL;
+ nor_size = 0;
+ filename = strtok(NULL, "\n");
+ }
+ plist_dict_insert_item(dict, "NorImageData", norimage_array);
+
+ int sz = 0;
+ char* xml = NULL;
+ plist_to_xml(dict, &xml, &sz);
+ debug("%s", xml);
+ free(xml);
+
+ restored_error_t ret = restored_send(client, dict);
+ if (ret != RESTORE_E_SUCCESS) {
+ error("ERROR: Unable to send kernelcache data\n");
+ plist_free(dict);
+ return -1;
+ }
+
+ plist_free(dict);
+ return 0;
+}
diff --git a/src/restore.h b/src/restore.h
new file mode 100644
index 0000000..644658a
--- /dev/null
+++ b/src/restore.h
@@ -0,0 +1,36 @@
+/*
+ * restore.h
+ * Functions for handling idevices in restore mode
+ *
+ * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef RESTORED_H
+#define RESTORED_H
+
+#include <libimobiledevice/restore.h>
+
+#include "restore.h"
+
+int restore_handle_progress_msg(restored_client_t client, plist_t msg);
+int restore_handle_status_msg(restored_client_t client, plist_t msg);
+int asr_send_system_image_data_from_file(idevice_t device, restored_client_t client, const char *filesystem);
+int restore_send_kernelcache(restored_client_t client, char *kernel_data, int len);
+int restore_send_nor_data(restored_client_t client, char* ipsw, plist_t tss);
+const char* restore_progress_string(unsigned int operation);
+
+#endif