diff options
| -rw-r--r-- | src/Makefile.am | 2 | ||||
| -rw-r--r-- | src/dfu.c | 28 | ||||
| -rw-r--r-- | src/dfu.h | 29 | ||||
| -rw-r--r-- | src/idevicerestore.c | 623 | ||||
| -rw-r--r-- | src/normal.c | 28 | ||||
| -rw-r--r-- | src/normal.h | 29 | ||||
| -rw-r--r-- | src/recovery.c | 269 | ||||
| -rw-r--r-- | src/recovery.h | 37 | ||||
| -rw-r--r-- | src/restore.c | 405 | ||||
| -rw-r--r-- | src/restore.h | 36 | 
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 | 
