diff options
| author | 2010-06-22 15:06:55 -0400 | |
|---|---|---|
| committer | 2010-06-22 15:06:55 -0400 | |
| commit | 38c965c16625d26915b3d4998a8a7e790c834d89 (patch) | |
| tree | 227333a4a327c66b23cad380ee8c9614c315aa5f /src/idevicerestore.c | |
| parent | 61db8cf5abc37ea0da1878961f209f3eb2ba31bf (diff) | |
| download | idevicerestore-38c965c16625d26915b3d4998a8a7e790c834d89.tar.gz idevicerestore-38c965c16625d26915b3d4998a8a7e790c834d89.tar.bz2 | |
Reverted rcg4u merge, didn't realize this was actually from posixninja branch
Diffstat (limited to 'src/idevicerestore.c')
| -rw-r--r-- | src/idevicerestore.c | 971 | 
1 files changed, 471 insertions, 500 deletions
| diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 69363fb..aaff4d6 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -23,7 +23,6 @@  #include <stdlib.h>  #include <string.h>  #include <unistd.h> -#include <getopt.h>  #include <plist/plist.h>  #include <libirecovery.h>  #include <libimobiledevice/restore.h> @@ -39,70 +38,46 @@  #include "recovery.h"  #include "idevicerestore.h" -int idevicerestore_quit = 0; -int idevicerestore_debug = 0; -int idevicerestore_erase = 0; -int idevicerestore_custom = 0; -int idevicerestore_verbose = 0; -int idevicerestore_exclude = 0; -int idevicerestore_mode = MODE_UNKNOWN; -idevicerestore_device_t* idevicerestore_device = NULL; - -static struct option long_opts[] = { -	{ "uuid",    required_argument,  NULL, 'u' }, -	{ "debug",   no_argument,        NULL, 'd' }, -	{ "verbose", no_argument,        NULL, 'v' }, -	{ "help",    no_argument,        NULL, 'h' }, -	{ "erase",   no_argument,        NULL, 'e' }, -	{ "custom",  no_argument,        NULL, 'c' }, -	{ "exclude", no_argument,        NULL, 'x' }, -	{ NULL, 0, NULL, 0} -}; +#define UNKNOWN_MODE   0 +#define DFU_MODE       1 +#define NORMAL_MODE    2 +#define RECOVERY_MODE  3 +#define RESTORE_MODE   4 -void usage(int argc, char* argv[]) { -	char *name = strrchr(argv[0], '/'); -	printf("Usage: %s [OPTIONS] FILE\n", (name ? name + 1 : argv[0])); -	printf("Restore/upgrade IPSW firmware FILE to an iPhone/iPod Touch.\n"); -	printf("  -u, --uuid UUID\ttarget specific device by its 40-digit device UUID\n"); -	printf("  -d, --debug\t\tenable communication debugging\n"); -	printf("  -v, --verbose\t\tenable verbose output\n"); -	printf("  -h, --help\t\tprints usage information\n"); -	printf("  -e, --erase\t\tperform a full restore, erasing all data\n"); -	printf("  -c, --custom\t\trestore with a custom firmware\n"); -	printf("  -x, --exclude\t\texclude nor/baseband upgrade\n"); -	printf("\n"); -} +int idevicerestore_debug = 0; +static int idevicerestore_mode = 0; +static int idevicerestore_quit = 0; +static int idevicerestore_custom = 0; + +void usage(int argc, char* argv[]); +int write_file(const char* filename, char* data, int size); +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); +int get_signed_component_by_name(char* ipsw, plist_t tss, char* component, char** pdata, int* psize); +int get_signed_component_by_path(char* ipsw, plist_t tss, char* path, char** pdata, int* psize);  int main(int argc, char* argv[]) {  	int opt = 0; -	int optindex = 0;  	char* ipsw = NULL;  	char* uuid = NULL;  	uint64_t ecid = 0; -	while ((opt = getopt_long(argc, argv, "vdhcexu:", long_opts, &optindex)) > 0) { +	while ((opt = getopt(argc, argv, "vdhcu:")) > 0) {  		switch (opt) {  		case 'h':  			usage(argc, argv);  			break; -		case 'd': -			idevicerestore_debug = 1; -			break; - -		case 'e': -			idevicerestore_erase = 1; +		case 'v': +			idevicerestore_debug += 1;  			break;  		case 'c':  			idevicerestore_custom = 1;  			break; -		case 'x': -			idevicerestore_exclude = 1; -			break; - -		case 'v': -			idevicerestore_verbose = 1; +		case 'd': +			idevicerestore_debug = 3;  			break;  		case 'u': @@ -111,608 +86,604 @@ int main(int argc, char* argv[]) {  		default:  			usage(argc, argv); -			return -1; +			break;  		}  	}  	argc -= optind;  	argv += optind; -	if (argc == 1) { +	if (argc == 1)  		ipsw = argv[0]; -	} else { -		usage(argc, argv); -		return -1; -	} - -	if(idevicerestore_debug) { -		idevice_set_debug_level(5); -	} - -	// check which mode the device is currently in so we know where to start -	idevicerestore_mode = check_mode(uuid); -	if (idevicerestore_mode < 0) { -		error("ERROR: Unable to discover current device state\n"); -		return -1; -	} -	// discover the device type -	int id = check_device(uuid); -	if (id < 0) { -		error("ERROR: Unable to discover device type\n"); +	if (ipsw == NULL) { +		error("ERROR: Please supply an IPSW\n");  		return -1;  	} -	idevicerestore_device = &idevicerestore_devices[id]; -	if (idevicerestore_mode == MODE_RESTORE) { -		if (restore_reboot(uuid) < 0) { -			error("ERROR: Unable to exit restore mode\n"); +	idevice_t device = NULL; +	irecv_client_t recovery = NULL; +	lockdownd_client_t lockdown = NULL; +	irecv_error_t recovery_error = IRECV_E_SUCCESS; +	idevice_error_t device_error = IDEVICE_E_SUCCESS; +	lockdownd_error_t lockdown_error = LOCKDOWN_E_SUCCESS; + +	/* determine recovery or normal mode */ +	info("Checking for device in normal mode...\n"); +	device_error = idevice_new(&device, uuid); +	if (device_error != IDEVICE_E_SUCCESS) { +		info("Checking for the device in recovery mode...\n"); +		recovery_error = irecv_open(&recovery); +		if (recovery_error != IRECV_E_SUCCESS) { +			error("ERROR: Unable to find device, is it plugged in?\n");  			return -1;  		} -	} +		info("Found device in recovery mode\n"); +		idevicerestore_mode = RECOVERY_MODE; -	// extract buildmanifest -	plist_t buildmanifest = NULL; -	info("Extracting BuildManifest from IPSW\n"); -	if (extract_buildmanifest(ipsw, &buildmanifest) < 0) { -		error("ERROR: Unable to extract BuildManifest from %s\n", ipsw); -		return -1; +	} else { +		info("Found device in normal mode\n"); +		idevicerestore_mode = NORMAL_MODE;  	} -	// choose whether this is an upgrade or a restore (default to upgrade) -	plist_t build_identity = NULL; -	if (idevicerestore_erase) { -		build_identity = get_build_identity(buildmanifest, 0); -		if (build_identity == NULL) { -			error("ERROR: Unable to find build any identities\n"); -			plist_free(buildmanifest); +	/* retrieve ECID */ +	if (idevicerestore_mode == NORMAL_MODE) { +		lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore"); +		if (lockdown_error != LOCKDOWN_E_SUCCESS) { +			error("ERROR: Unable to connect to lockdownd\n"); +			idevice_free(device);  			return -1;  		} -	} else { -		build_identity = get_build_identity(buildmanifest, 1); -		if (build_identity == NULL) { -			build_identity = get_build_identity(buildmanifest, 0); -			if (build_identity == NULL) { -				error("ERROR: Unable to find build any identities\n"); -				plist_free(buildmanifest); -				return -1; -			} -			info("No upgrade ramdisk found, default to full restore\n"); +		plist_t unique_chip_node = NULL; +		lockdown_error = lockdownd_get_value(lockdown, NULL, "UniqueChipID", &unique_chip_node); +		if (lockdown_error != LOCKDOWN_E_SUCCESS) { +			error("ERROR: Unable to get UniqueChipID from lockdownd\n"); +			lockdownd_client_free(lockdown); +			idevice_free(device); +			return -1;  		} -	} -	// devices are listed in order from oldest to newest -	// devices that come after iPod2g require personalized firmwares -	plist_t tss_request = NULL; -	plist_t tss = NULL; -	if (idevicerestore_device->device_id > DEVICE_IPOD2G) { -		info("Creating TSS request\n"); -		// fetch the device's ECID for the TSS request -		if (get_ecid(uuid, &ecid) < 0 || ecid == 0) { -			error("ERROR: Unable to find device ECID\n"); +		if (!unique_chip_node || plist_get_node_type(unique_chip_node) != PLIST_UINT) { +			error("ERROR: Unable to get ECID\n"); +			lockdownd_client_free(lockdown); +			idevice_free(device);  			return -1;  		} + +		plist_get_uint_val(unique_chip_node, &ecid); +		lockdownd_client_free(lockdown); +		plist_free(unique_chip_node); +		idevice_free(device); +		lockdown = NULL; +		device = NULL; + +	} else if (idevicerestore_mode == RECOVERY_MODE) { +		recovery_error = irecv_get_ecid(recovery, &ecid); +		if (recovery_error != IRECV_E_SUCCESS) { +			error("ERROR: Unable to get device ECID\n"); +			irecv_close(recovery); +			return -1; +		} +		irecv_close(recovery); +		recovery = NULL; +	} + +	if (ecid != 0) {  		info("Found ECID %llu\n", ecid); +	} else { +		error("Unable to find device ECID\n"); +		return -1; +	} -		// fetch the SHSH blobs for this build identity -		if (get_shsh_blobs(ecid, build_identity, &tss) < 0) { -			// this might fail if the TSS server doesn't have the saved blobs for the -			// update identity, so go ahead and try again with the restore identity -			if (idevicerestore_erase != 1) { -				info("Unable to fetch SHSH blobs for upgrade, retrying with full restore\n"); -				build_identity = get_build_identity(buildmanifest, 0); -				if (build_identity == NULL) { -					error("ERROR: Unable to find restore identity\n"); -					plist_free(buildmanifest); -					return -1; -				} +	/* parse buildmanifest */ +	int buildmanifest_size = 0; +	char* buildmanifest_data = NULL; +	info("Extracting BuildManifest.plist from IPSW\n"); +	if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &buildmanifest_data, &buildmanifest_size) < 0) { +		error("ERROR: Unable to extract BuildManifest.plist IPSW\n"); +		return -1; +	} -				if (get_shsh_blobs(ecid, build_identity, &tss) < 0) { -					// if this fails then no SHSH blobs have been saved for this firmware -					error("ERROR: Unable to fetch SHSH blobs for this firmware\n"); -					plist_free(buildmanifest); -					return -1; -				} +	plist_t manifest = NULL; +	plist_from_xml(buildmanifest_data, buildmanifest_size, &manifest); -			} else { -				error("ERROR: Unable to fetch SHSH blobs for this firmware\n"); -				plist_free(buildmanifest); -				return -1; -			} -		} +	info("Creating TSS request\n"); +	plist_t tss_request = tss_create_request(manifest, ecid); +	if (tss_request == NULL) { +		error("ERROR: Unable to create TSS request\n"); +		plist_free(manifest); +		return -1;  	} +	plist_free(manifest); -	// Extract filesystem from IPSW and return its name +	info("Sending TSS request\n"); +	plist_t tss_response = tss_send_request(tss_request); +	if (tss_response == NULL) { +		error("ERROR: Unable to get response from TSS server\n"); +		plist_free(tss_request); +		return -1; +	} +	info("Got TSS response\n"); + +	// Get name of filesystem DMG in IPSW  	char* filesystem = NULL; -	if (extract_filesystem(ipsw, build_identity, &filesystem) < 0) { -		error("ERROR: Unable to extract filesystem from IPSW\n"); -		if (tss) -			plist_free(tss); -		plist_free(buildmanifest); +	plist_t filesystem_node = plist_dict_get_item(tss_request, "OS"); +	if (!filesystem_node || plist_get_node_type(filesystem_node) != PLIST_DICT) { +		error("ERROR: Unable to find filesystem node\n"); +		plist_free(tss_request);  		return -1;  	} -	// if the device is in normal mode, place device into recovery mode -	if (idevicerestore_mode == MODE_NORMAL) { -		info("Entering recovery mode...\n"); -		if (normal_enter_recovery(uuid) < 0) { -			error("ERROR: Unable to place device into recovery mode\n"); -			if (tss) -				plist_free(tss); -			plist_free(buildmanifest); -			return -1; -		} +	plist_t filesystem_info_node = plist_dict_get_item(filesystem_node, "Info"); +	if (!filesystem_info_node || plist_get_node_type(filesystem_info_node) != PLIST_DICT) { +		error("ERROR: Unable to find filesystem info node\n"); +		plist_free(tss_request); +		return -1;  	} -	// if the device is in DFU mode, place device into recovery mode -	if (idevicerestore_mode == MODE_DFU) { -		if (dfu_enter_recovery(ipsw, tss) < 0) { -			error("ERROR: Unable to place device into recovery mode\n"); -			plist_free(buildmanifest); -			if (tss) -				plist_free(tss); -			return -1; -		} +	plist_t filesystem_info_path_node = plist_dict_get_item(filesystem_info_node, "Path"); +	if (!filesystem_info_path_node || plist_get_node_type(filesystem_info_path_node) != PLIST_STRING) { +		error("ERROR: Unable to find filesystem info path node\n"); +		plist_free(tss_request); +		return -1;  	} +	plist_get_string_val(filesystem_info_path_node, &filesystem); +	plist_free(tss_request); -	// if the device is in recovery mode, place device into restore mode -	if (idevicerestore_mode == MODE_RECOVERY) { -		if (recovery_enter_restore(uuid, ipsw, tss) < 0) { -			error("ERROR: Unable to place device into restore mode\n"); -			plist_free(buildmanifest); -			if (tss) -				plist_free(tss); -			return -1; -		} +	info("Extracting filesystem from IPSW\n"); +	if (ipsw_extract_to_file(ipsw, filesystem, filesystem) < 0) { +		error("ERROR: Unable to extract filesystem\n"); +		return -1;  	} -	// device is finally in restore mode, let's do this -	if (idevicerestore_mode == MODE_RESTORE) { -		info("Restoring device... \n"); -		if (restore_device(uuid, ipsw, tss, filesystem) < 0) { -			error("ERROR: Unable to restore device\n"); +	/* place device into recovery mode if required */ +	if (idevicerestore_mode == NORMAL_MODE) { +		info("Entering recovery mode...\n"); +		device_error = idevice_new(&device, uuid); +		if (device_error != IDEVICE_E_SUCCESS) { +			error("ERROR: Unable to find device\n"); +			plist_free(tss_response);  			return -1;  		} -	} -	// device has finished restoring, lets see if we need to activate -	if (idevicerestore_mode == MODE_NORMAL) { -		info("Checking activation status\n"); -		int activation = activate_check_status(uuid); -		if (activation < 0) { -			error("ERROR: Unable to check activation status\n"); +		lockdown_error = lockdownd_client_new_with_handshake(device, &lockdown, "idevicerestore"); +		if (lockdown_error != LOCKDOWN_E_SUCCESS) { +			error("ERROR: Unable to connect to lockdownd service\n"); +			plist_free(tss_response); +			idevice_free(device);  			return -1;  		} -		if (activation == 0) { -			info("Activating device... \n"); -			if (activate_device(uuid) < 0) { -				error("ERROR: Unable to activate device\n"); -				return -1; -			} +		lockdown_error = lockdownd_enter_recovery(lockdown); +		if (lockdown_error != LOCKDOWN_E_SUCCESS) { +			error("ERROR: Unable to place device in recovery mode\n"); +			lockdownd_client_free(lockdown); +			plist_free(tss_response); +			idevice_free(device); +			return -1;  		} -	} - -	info("Cleaning up...\n"); -	if (filesystem) -		unlink(filesystem); - -	info("DONE\n"); -	return 0; -} -int check_mode(const char* uuid) { -	int mode = MODE_UNKNOWN; +		lockdownd_client_free(lockdown); +		idevice_free(device); +		lockdown = NULL; +		device = NULL; +	} -	if (recovery_check_mode() == 0) { -		info("Found device in recovery mode\n"); -		mode = MODE_RECOVERY; +	/* upload data to make device boot restore mode */ +	if (recovery_send_ibec(ipsw, tss_response) < 0) { +		error("ERROR: Unable to send iBEC\n"); +		plist_free(tss_response); +		return -1;  	} +	sleep(1); -	else if (dfu_check_mode() == 0) { -		info("Found device in DFU mode\n"); -		mode = MODE_DFU; +	if (recovery_send_applelogo(ipsw, tss_response) < 0) { +		error("ERROR: Unable to send AppleLogo\n"); +		plist_free(tss_response); +		return -1;  	} -	else if (normal_check_mode(uuid) == 0) { -		info("Found device in normal mode\n"); -		mode = MODE_NORMAL; +	if (recovery_send_devicetree(ipsw, tss_response) < 0) { +		error("ERROR: Unable to send DeviceTree\n"); +		plist_free(tss_response); +		return -1;  	} -	else if (restore_check_mode(uuid) == 0) { -		info("Found device in restore mode\n"); -		mode = MODE_RESTORE; +	if (recovery_send_ramdisk(ipsw, tss_response) < 0) { +		error("ERROR: Unable to send Ramdisk\n"); +		plist_free(tss_response); +		return -1;  	} -	return mode; -} +	// 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(); -int check_device(const char* uuid) { -	int device = DEVICE_UNKNOWN; -	uint32_t bdid = 0; -	uint32_t cpid = 0; +	if (recovery_send_kernelcache(ipsw, tss_response) < 0) { +		error("ERROR: Unable to send KernelCache\n"); +		plist_free(tss_response); +		return -1; +	} -	switch (idevicerestore_mode) { -	case MODE_RESTORE: -		device = restore_check_device(uuid); -		if (device < 0) { -			device = DEVICE_UNKNOWN; -		} -		break; +	idevice_event_subscribe(&device_callback, NULL); +	info("Waiting for device to enter restore mode\n"); +	// block program until device has entered restore mode +	while (idevicerestore_mode != RESTORE_MODE) { +		sleep(1); +	} -	case MODE_NORMAL: -		device = normal_check_device(uuid); -		if (device < 0) { -			device = DEVICE_UNKNOWN; -		} -		break; +	device_error = idevice_new(&device, uuid); +	if (device_error != IDEVICE_E_SUCCESS) { +		error("ERROR: Unable to open device\n"); +		plist_free(tss_response); +		return -1; +	} -	case MODE_DFU: -	case MODE_RECOVERY: -		if (get_cpid(uuid, &cpid) < 0) { -			error("ERROR: Unable to get device CPID\n"); -			break; -		} +	restored_client_t restore = NULL; +	restored_error_t restore_error = restored_client_new(device, &restore, "idevicerestore"); +	if (restore_error != RESTORE_E_SUCCESS) { +		error("ERROR: Unable to start restored client\n"); +		plist_free(tss_response); +		idevice_free(device); +		return -1; +	} -		switch (cpid) { -		case CPID_IPHONE2G: -			// iPhone1,1 iPhone1,2 and iPod1,1 all share the same ChipID -			//   so we need to check the BoardID -			if (get_bdid(uuid, &bdid) < 0) { -				error("ERROR: Unable to get device BDID\n"); -				break; +	char* type = NULL; +	uint64_t version = 0; +	if (restored_query_type(restore, &type, &version) != RESTORE_E_SUCCESS) { +		error("ERROR: Device is not in restore mode. QueryType returned \"%s\"\n", type); +		plist_free(tss_response); +		restored_client_free(restore); +		idevice_free(device); +		return -1; +	} +	info("Device has successfully entered restore mode\n"); + +	/* start restore process */ +	char* kernelcache = NULL; +	info("Restore protocol version is %llu.\n", version); +	restore_error = restored_start_restore(restore); +	if (restore_error == RESTORE_E_SUCCESS) { +		while (!idevicerestore_quit) { +			plist_t message = NULL; +			restore_error = restored_receive(restore, &message); +			plist_t msgtype_node = plist_dict_get_item(message, "MsgType"); +			if (msgtype_node && PLIST_STRING == plist_get_node_type(msgtype_node)) { +				char *msgtype = NULL; +				plist_get_string_val(msgtype_node, &msgtype); +				if (!strcmp(msgtype, "ProgressMsg")) { +					restore_error = restore_handle_progress_msg(restore, message); + +				} else if (!strcmp(msgtype, "DataRequestMsg")) { +					// device is requesting data to be sent +					plist_t datatype_node = plist_dict_get_item(message, "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, restore, filesystem); + +						} else if (!strcmp(datatype, "KernelCache")) { +							int kernelcache_size = 0; +							char* kernelcache_data = NULL; +							if (get_signed_component_by_name(ipsw, tss_response, "KernelCache", &kernelcache_data, &kernelcache_size) < 0) { +								error("ERROR: Unable to get kernelcache file\n"); +								return -1; +							} +							restore_send_kernelcache(restore, kernelcache_data, kernelcache_size); +							free(kernelcache_data); + +						} else if (!strcmp(datatype, "NORData")) { +							restore_send_nor_data(restore, ipsw, tss_response); + +						} else { +							// Unknown DataType!! +							error("Unknown DataType\n"); +							return -1; +						} +					} + +				} else if (!strcmp(msgtype, "StatusMsg")) { +					restore_error = restore_handle_status_msg(restore, message); + +				} else { +					info("Received unknown message type: %s\n", msgtype); +				}  			} -			switch (bdid) { -			case BDID_IPHONE2G: -				device = DEVICE_IPHONE2G; -				break; - -			case BDID_IPHONE3G: -				device = DEVICE_IPHONE3G; -				break; - -			case BDID_IPOD1G: -				device = DEVICE_IPOD1G; -				break; - -			default: -				device = DEVICE_UNKNOWN; -				break; +			if (RESTORE_E_SUCCESS != restore_error) { +				error("Invalid return status %d\n", restore_error); +				//idevicerestore_quit = 1;  			} -			break; - -		case CPID_IPHONE3GS: -			device = DEVICE_IPHONE3GS; -			break; - -		case CPID_IPOD2G: -			device = DEVICE_IPOD2G; -			break; -		case CPID_IPOD3G: -			device = DEVICE_IPOD3G; -			break; - -		case CPID_IPAD1G: -			device = DEVICE_IPAD1G; -			break; - -		default: -			device = DEVICE_UNKNOWN; -			break; +			plist_free(message);  		} -		break; - -	default: -		device = DEVICE_UNKNOWN; -		break; - +	} else { +		error("ERROR: Could not start restore. %d\n", restore_error);  	} -	return device; +	restored_client_free(restore); +	plist_free(tss_response); +	idevice_free(device); +	unlink(filesystem); +	return 0;  } -int get_bdid(const char* uuid, uint32_t* bdid) { -	switch (idevicerestore_mode) { -	case MODE_NORMAL: -		if (normal_get_bdid(uuid, bdid) < 0) { -			*bdid = -1; -			return -1; -		} -		break; - -	case MODE_DFU: -	case MODE_RECOVERY: -		if (recovery_get_bdid(bdid) < 0) { -			*bdid = -1; -			return -1; -		} -		break; - -	default: -		error("ERROR: Device is in an invalid state\n"); -		return -1; +void device_callback(const idevice_event_t* event, void *user_data) { +	if (event->event == IDEVICE_DEVICE_ADD) { +		idevicerestore_mode = RESTORE_MODE; +	} else if(event->event == IDEVICE_DEVICE_REMOVE) { +		idevicerestore_quit = 1;  	} - -	return 0;  } -int get_cpid(const char* uuid, uint32_t* cpid) { -	switch (idevicerestore_mode) { -	case MODE_NORMAL: -		if (normal_get_cpid(uuid, cpid) < 0) { -			*cpid = 0; -			return -1; -		} -		break; - -	case MODE_DFU: -	case MODE_RECOVERY: -		if (recovery_get_cpid(cpid) < 0) { -			*cpid = 0; -			return -1; -		} -		break; +void usage(int argc, char* argv[]) { +	char *name = strrchr(argv[0], '/'); +	printf("Usage: %s [OPTIONS] FILE\n", (name ? name + 1 : argv[0])); +	printf("Restore/upgrade IPSW firmware FILE to an iPhone/iPod Touch.\n"); +	printf("  -d, \t\tenable communication debugging\n"); +	printf("  -u, \t\ttarget specific device by its 40-digit device UUID\n"); +	printf("  -h, \t\tprints usage information\n"); +	printf("  -c, \t\trestore with a custom firmware\n"); +	printf("  -v, \t\tenable incremental levels of verboseness\n"); +	printf("\n"); +	exit(1); +} -	default: -		error("ERROR: Device is in an invalid state\n"); +int write_file(const char* filename, char* data, int size) { +	debug("Writing data to %s\n", filename); +	FILE* file = fopen(filename, "wb"); +	if (file == NULL) { +		error("read_file: Unable to open file %s\n", filename);  		return -1;  	} -	return 0; -} - -int get_ecid(const char* uuid, uint64_t* ecid) { -	switch (idevicerestore_mode) { -	case MODE_NORMAL: -		if (normal_get_ecid(uuid, ecid) < 0) { -			*ecid = 0; -			return -1; -		} -		break; - -	case MODE_DFU: -	case MODE_RECOVERY: -		if (recovery_get_ecid(ecid) < 0) { -			*ecid = 0; -			return -1; -		} -		break; +	int bytes = fwrite(data, 1, size, file); +	fclose(file); -	default: -		error("ERROR: Device is in an invalid state\n"); +	if (bytes != size) { +		error("ERROR: Unable to write entire file: %s: %d %d\n", filename, bytes, size);  		return -1;  	} -	return 0; +	return size;  } -int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest) { -	int size = 0; -	char* data = NULL; -	int device = idevicerestore_device->device_id; -	if (device >= DEVICE_IPHONE2G && device <= DEVICE_IPOD2G) { -		// Older devices that don't require personalized firmwares use BuildManifesto.plist -		if (ipsw_extract_to_memory(ipsw, "BuildManifesto.plist", &data, &size) < 0) { -			return -1; +int get_tss_data_by_path(plist_t tss, const char* path, char** pname, char** pblob) { +	*pname = NULL; +	*pblob = NULL; + +	char* key = NULL; +	plist_t tss_entry = NULL; +	plist_dict_iter iter = NULL; +	plist_dict_new_iter(tss, &iter); +	while (1) { +		plist_dict_next_item(tss, iter, &key, &tss_entry); +		if (key == NULL) +			break; + +		if (!tss_entry || plist_get_node_type(tss_entry) != PLIST_DICT) { +			continue;  		} -	} else if (device >= DEVICE_IPHONE3GS && device <= DEVICE_IPAD1G) { -		// Whereas newer devices that do require personalized firmwares use BuildManifest.plist -		if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &data, &size) < 0) { +		char* entry_path = NULL; +		plist_t entry_path_node = plist_dict_get_item(tss_entry, "Path"); +		if (!entry_path_node || plist_get_node_type(entry_path_node) != PLIST_STRING) { +			error("ERROR: Unable to find TSS path node in entry %s\n", key);  			return -1;  		} +		plist_get_string_val(entry_path_node, &entry_path); +		if (strcmp(path, entry_path) == 0) { +			char* blob = NULL; +			uint64_t blob_size = 0; +			plist_t blob_node = plist_dict_get_item(tss_entry, "Blob"); +			if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) { +				error("ERROR: Unable to find TSS blob node in entry %s\n", key); +				return -1; +			} +			plist_get_data_val(blob_node, &blob, &blob_size); +			*pname = key; +			*pblob = blob; +			return 0; +		} -	} else { -		return -1; +		free(key);  	} +	plist_free(tss_entry); -	plist_from_xml(data, size, buildmanifest); -	return 0; +	return -1;  } -plist_t get_build_identity(plist_t buildmanifest, uint32_t identity) { +int get_tss_data_by_name(plist_t tss, const char* entry, char** ppath, char** pblob) { +	*ppath = NULL; +	*pblob = NULL; -	// fetch build identities array from BuildManifest -	plist_t build_identities_array = plist_dict_get_item(buildmanifest, "BuildIdentities"); -	if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) { -		error("ERROR: Unable to find build identities node\n"); -		return NULL; +	plist_t node = plist_dict_get_item(tss, entry); +	if (!node || plist_get_node_type(node) != PLIST_DICT) { +		error("ERROR: Unable to find %s entry in TSS response\n", entry); +		return -1;  	} -	// check and make sure this identity exists in buildmanifest -	if (identity >= plist_array_get_size(build_identities_array)) { -		return NULL; +	char* path = NULL; +	plist_t path_node = plist_dict_get_item(node, "Path"); +	if (!path_node || plist_get_node_type(path_node) != PLIST_STRING) { +		error("ERROR: Unable to find %s path in entry\n", path); +		return -1;  	} +	plist_get_string_val(path_node, &path); -	plist_t build_identity = plist_array_get_item(build_identities_array, identity); -	if (!build_identity || plist_get_node_type(build_identity) != PLIST_DICT) { -		error("ERROR: Unable to find build identities node\n"); -		return NULL; +	char* blob = NULL; +	uint64_t blob_size = 0; +	plist_t blob_node = plist_dict_get_item(node, "Blob"); +	if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) { +		error("ERROR: Unable to find %s blob in entry\n", path); +		free(path); +		return -1;  	} +	plist_get_data_val(blob_node, &blob, &blob_size); -	return plist_copy(build_identity); +	*ppath = path; +	*pblob = blob; +	return 0;  } -int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss) { -	plist_t request = NULL; -	plist_t response = NULL; -	*tss = NULL; +int get_signed_component_by_name(char* ipsw, plist_t tss, char* component, char** pdata, int* psize) { +	int size = 0; +	char* data = NULL; +	char* path = NULL; +	char* blob = NULL; +	img3_file* img3 = NULL; +	irecv_error_t error = 0; -	request = tss_create_request(build_identity, ecid); -	if (request == NULL) { -		error("ERROR: Unable to create TSS request\n"); +	info("Extracting %s from TSS response\n", component); +	if (get_tss_data_by_name(tss, component, &path, &blob) < 0) { +		error("ERROR: Unable to get data for TSS %s entry\n", component);  		return -1;  	} -	info("Sending TSS request\n"); -	response = tss_send_request(request); -	if (response == NULL) { -		plist_free(request); +	info("Extracting %s from %s\n", path, ipsw); +	if (ipsw_extract_to_memory(ipsw, path, &data, &size) < 0) { +		error("ERROR: Unable to extract %s from %s\n", path, ipsw); +		free(path); +		free(blob);  		return -1;  	} -	plist_free(request); -	*tss = response; -	return 0; -} - -int extract_filesystem(const char* ipsw, plist_t build_identity, char** filesystem) { -	char* filename = NULL; - -	plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest"); -	if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { -		error("ERROR: Unable to find manifest node\n"); +	img3 = img3_parse_file(data, size); +	if (img3 == NULL) { +		error("ERROR: Unable to parse IMG3: %s\n", path); +		free(data); +		free(path); +		free(blob);  		return -1;  	} +	if (data) { +		free(data); +		data = NULL; +	} -	plist_t filesystem_node = plist_dict_get_item(manifest_node, "OS"); -	if (!filesystem_node || plist_get_node_type(filesystem_node) != PLIST_DICT) { -		error("ERROR: Unable to find filesystem node\n"); -		return -1; +	if (idevicerestore_custom == 0) { +		if (img3_replace_signature(img3, blob) < 0) { +			error("ERROR: Unable to replace IMG3 signature\n"); +			free(path); +			free(blob); +			return -1; +		}  	} -	plist_t filesystem_info_node = plist_dict_get_item(filesystem_node, "Info"); -	if (!filesystem_info_node || plist_get_node_type(filesystem_info_node) != PLIST_DICT) { -		error("ERROR: Unable to find filesystem info node\n"); +	if (img3_get_data(img3, &data, &size) < 0) { +		error("ERROR: Unable to reconstruct IMG3\n"); +		img3_free(img3); +		free(path);  		return -1;  	} -	plist_t filesystem_info_path_node = plist_dict_get_item(filesystem_info_node, "Path"); -	if (!filesystem_info_path_node || plist_get_node_type(filesystem_info_path_node) != PLIST_STRING) { -		error("ERROR: Unable to find filesystem info path node\n"); -		return -1; +	if (idevicerestore_debug) { +		char* out = strrchr(path, '/'); +		if (out != NULL) { +			out++; +		} else { +			out = path; +		} +		write_file(out, data, size);  	} -	plist_get_string_val(filesystem_info_path_node, &filename); -	info("Extracting filesystem from IPSW\n"); -	if (ipsw_extract_to_file(ipsw, filename, filename) < 0) { -		error("ERROR: Unable to extract filesystem\n"); -		return -1; +	if (img3) { +		img3_free(img3); +		img3 = NULL; +	} +	if (blob) { +		free(blob); +		blob = NULL; +	} +	if (path) { +		free(path); +		path = NULL;  	} -	*filesystem = filename; +	*pdata = data; +	*psize = size;  	return 0;  } -int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size) { +int get_signed_component_by_path(char* ipsw, plist_t tss, char* path, char** pdata, int* psize) { +	int size = 0; +	char* data = NULL; +	char* name = NULL; +	char* blob = NULL;  	img3_file* img3 = NULL; -	uint32_t component_size = 0; -	char* component_data = NULL; -	char* component_blob = NULL; -	char* component_name = NULL; - -	component_name = strrchr(path, '/'); -	if (component_name != NULL) component_name++; -	else component_name = (char*) path; - -	info("Extracting %s\n", component_name); -	if (ipsw_extract_to_memory(ipsw, path, &component_data, &component_size) < 0) { -		error("ERROR: Unable to extract %s from %s\n", component_name, ipsw); +	irecv_error_t error = 0; + +	info("Extracting %s from TSS response\n", path); +	if (get_tss_data_by_path(tss, path, &name, &blob) < 0) { +		error("ERROR: Unable to get data for TSS %s entry\n", path);  		return -1;  	} -	img3 = img3_parse_file(component_data, component_size); -	if (img3 == NULL) { -		error("ERROR: Unable to parse IMG3: %s\n", component_name); -		free(component_data); +	info("Extracting %s from %s\n", path, ipsw); +	if (ipsw_extract_to_memory(ipsw, path, &data, &size) < 0) { +		error("ERROR: Unable to extract %s from %s\n", path, ipsw); +		free(path); +		free(blob);  		return -1;  	} -	free(component_data); -	if (tss_get_blob_by_path(tss, path, &component_blob) < 0) { -		error("ERROR: Unable to get SHSH blob for TSS %s entry\n", component_name); -		img3_free(img3); +	img3 = img3_parse_file(data, size); +	if (img3 == NULL) { +		error("ERROR: Unable to parse IMG3: %s\n", path); +		free(data); +		free(path); +		free(blob);  		return -1;  	} +	if (data) { +		free(data); +		data = NULL; +	} -	if (idevicerestore_device->device_id > DEVICE_IPOD2G && idevicerestore_custom == 0) { -		if (img3_replace_signature(img3, component_blob) < 0) { +	if (idevicerestore_custom == 0) { +		if (img3_replace_signature(img3, blob) < 0) {  			error("ERROR: Unable to replace IMG3 signature\n"); -			free(component_blob); -			img3_free(img3); +			free(name); +			free(blob);  			return -1;  		}  	} -	free(component_blob); -	if (img3_get_data(img3, &component_data, &component_size) < 0) { +	if (img3_get_data(img3, &data, &size) < 0) {  		error("ERROR: Unable to reconstruct IMG3\n");  		img3_free(img3); +		free(name);  		return -1;  	} -	img3_free(img3);  	if (idevicerestore_debug) { -		write_file(component_name, component_data, component_size); -	} - -	*data = component_data; -	*size = component_size; -	return 0; -} - -int write_file(const char* filename, const void* data, size_t size) { -	size_t bytes = 0; -	FILE* file = NULL; - -	info("Writing data to %s\n", filename); -	file = fopen(filename, "wb"); -	if (file == NULL) { -		error("read_file: Unable to open file %s\n", filename); -		return -1; -	} - -	bytes = fwrite(data, 1, size, file); -	fclose(file); - -	if (bytes != size) { -		error("ERROR: Unable to write entire file: %s: %d %d\n", filename, bytes, size); -		return -1; +		char* out = strrchr(path, '/'); +		if (out != NULL) { +			out++; +		} else { +			out = path; +		} +		write_file(out, data, size);  	} -	return size; -} - -int read_file(const char* filename, char** data, uint32_t* size) { -	size_t bytes = 0; -	size_t length = 0; -	FILE* file = NULL; -	char* buffer = NULL; -	debug("Reading data from %s\n", filename); - -	*size = 0; -	*data = NULL; - -	file = fopen(filename, "rb"); -	if (file == NULL) { -		error("read_file: File %s not found\n", filename); -		return -1; +	if (img3) { +		img3_free(img3); +		img3 = NULL;  	} - -	fseek(file, 0, SEEK_END); -	length = ftell(file); -	rewind(file); - -	buffer = (char*) malloc(length); -	if(buffer == NULL) { -		error("ERROR: Out of memory\n"); -		fclose(file); -		return -1; +	if (blob) { +		free(blob); +		blob = NULL;  	} -	bytes = fread(buffer, 1, length, file); -	fclose(file); - -	if(bytes != length) { -		error("ERROR: Unable to read entire file\n"); -		free(buffer); -		return -1; +	if (path) { +		free(name); +		name = NULL;  	} -	*size = length; -	*data = buffer; +	*pdata = data; +	*psize = size;  	return 0;  } - | 
