diff options
Diffstat (limited to 'src/common.c')
| -rw-r--r-- | src/common.c | 537 | 
1 files changed, 333 insertions, 204 deletions
| diff --git a/src/common.c b/src/common.c index 4dbabc0..70f0742 100644 --- a/src/common.c +++ b/src/common.c @@ -35,6 +35,8 @@  #include <sys/stat.h>  #include <fcntl.h>  #include <ctype.h> +#include <libimobiledevice-glue/thread.h> +#include <libimobiledevice-glue/collection.h>  #ifdef WIN32  #include <windows.h> @@ -56,6 +58,13 @@  #define MAX_PRINT_LEN 64*1024 +int global_quit_flag = 0; +static const char* STARS  = "******************************************************************************"; +static const char* SPACES = "                                                                              "; +static const char* POUNDS = "##############################################################################"; + +static uint32_t progress_unique_tag = 1; +  struct idevicerestore_mode_t idevicerestore_modes[] = {  	{  0, "Unknown"  },  	{  1, "WTF"      }, @@ -63,106 +72,22 @@ struct idevicerestore_mode_t idevicerestore_modes[] = {  	{  3, "Recovery" },  	{  4, "Restore"  },  	{  5, "Normal"   }, +	{  6, "Port DFU" },  };  int idevicerestore_debug = 0; -#define idevicerestore_err_buff_size 256 -static char idevicerestore_err_buff[idevicerestore_err_buff_size] = {0, }; - -static FILE* info_stream = NULL; -static FILE* error_stream = NULL; -static FILE* debug_stream = NULL; - -static int info_disabled = 0; -static int error_disabled = 0; -static int debug_disabled = 0; - -void info(const char* format, ...) -{ -	if (info_disabled) return; -	va_list vargs; -	va_start(vargs, format); -	vfprintf((info_stream) ? info_stream : stdout, format, vargs); -	va_end(vargs); -} - -void error(const char* format, ...) -{ -	va_list vargs, vargs2; -	va_start(vargs, format); -	va_copy(vargs2, vargs); -	vsnprintf(idevicerestore_err_buff, idevicerestore_err_buff_size, format, vargs); -	va_end(vargs); -	if (!error_disabled) { -		vfprintf((error_stream) ? error_stream : stderr, format, vargs2); -	} -	va_end(vargs2); -} - -void debug(const char* format, ...) -{ -	if (debug_disabled) return; -	if (!idevicerestore_debug) { -		return; -	} -	va_list vargs; -	va_start(vargs, format); -	vfprintf((debug_stream) ? debug_stream : stderr, format, vargs); -	va_end(vargs); -} - -void idevicerestore_set_info_stream(FILE* strm) -{ -	if (strm) { -		info_disabled = 0; -		info_stream = strm; -	} else { -		info_disabled = 1; -	} -} - -void idevicerestore_set_error_stream(FILE* strm) -{ -	if (strm) { -		error_disabled = 0; -		error_stream = strm; -	} else { -		error_disabled = 1; -	} -} - -void idevicerestore_set_debug_stream(FILE* strm) -{ -	if (strm) { -		debug_disabled = 0; -		debug_stream = strm; -	} else { -		debug_disabled = 1; -	} -} - -const char* idevicerestore_get_error(void) -{ -	if (idevicerestore_err_buff[0] == 0) { -		return NULL; -	} else { -		char* p = NULL; -		while ((strlen(idevicerestore_err_buff) > 0) && (p = strrchr(idevicerestore_err_buff, '\n'))) { -			p[0] = '\0'; -		} -		return (const char*)idevicerestore_err_buff; -	} -} +static void (*banner_func)(const char*) = NULL; +static void (*banner_hide_func)(void) = NULL;  int write_file(const char* filename, const void* data, size_t size) {  	size_t bytes = 0;  	FILE* file = NULL; -	debug("Writing data to %s\n", filename); +	logger(LL_DEBUG, "Writing data to %s\n", filename);  	file = fopen(filename, "wb");  	if (file == NULL) { -		error("write_file: Unable to open file %s\n", filename); +		logger(LL_ERROR, "write_file: Unable to open file %s\n", filename);  		return -1;  	} @@ -170,7 +95,7 @@ int write_file(const char* filename, const void* data, size_t size) {  	fclose(file);  	if (bytes != size) { -		error("ERROR: Unable to write entire file: %s: %d of %d\n", filename, (int)bytes, (int)size); +		logger(LL_ERROR, "Unable to write entire file: %s: %d of %d\n", filename, (int)bytes, (int)size);  		return -1;  	} @@ -184,26 +109,26 @@ int read_file(const char* filename, void** data, size_t* size) {  	char* buffer = NULL;  	struct stat fst; -	debug("Reading data from %s\n", filename); +	logger(LL_DEBUG, "Reading data from %s\n", filename);  	*size = 0;  	*data = NULL;  	file = fopen(filename, "rb");  	if (file == NULL) { -		error("read_file: cannot open %s: %s\n", filename, strerror(errno)); +		logger(LL_ERROR, "read_file: cannot open %s: %s\n", filename, strerror(errno));  		return -1;  	}  	if (fstat(fileno(file), &fst) < 0) { -		error("read_file: fstat: %s\n", strerror(errno)); +		logger(LL_ERROR, "read_file: fstat: %s\n", strerror(errno));  		return -1;  	}  	length = fst.st_size;  	buffer = (char*) malloc(length);  	if (buffer == NULL) { -		error("ERROR: Out of memory\n"); +		logger(LL_ERROR, "Out of memory\n");  		fclose(file);  		return -1;  	} @@ -211,7 +136,7 @@ int read_file(const char* filename, void** data, size_t* size) {  	fclose(file);  	if (bytes != length) { -		error("ERROR: Unable to read entire file\n"); +		logger(LL_ERROR, "Unable to read entire file\n");  		free(buffer);  		return -1;  	} @@ -221,32 +146,308 @@ int read_file(const char* filename, void** data, size_t* size) {  	return 0;  } -void debug_plist(plist_t plist) { -	uint32_t size = 0; -	char* data = NULL; -	plist_to_xml(plist, &data, &size); -	if (size <= MAX_PRINT_LEN) -		info("%s:printing %i bytes plist:\n%s", __FILE__, size, data); -	else -		info("%s:supressed printing %i bytes plist...\n", __FILE__, size); -	free(data); +int process_text_lines(const char* text, int maxwidth, struct tuple** lines_out, int* maxlen_out) +{ +	if (!text) return 0; +	int len = strlen(text); +	int numlines = 0; +	int maxlen = 0; +	int linestart = 0; +	int linelen = 0; +	int lastspace = 0; +	int maxlines = 8; +	int count = 0; +	struct tuple* lines = (struct tuple*)malloc(sizeof(struct tuple) * maxlines); +	int i = 0; +	while (i <= len) { +		int split_line = 0; +		if ((text[i] & 0xE0) == 0xC0) i += 1; +		else if ((text[i] & 0xF0) == 0xE0) i += 2; +		else if ((text[i] & 0xF8) == 0xF0) i += 3; +		if (i > len) i = len; +		linelen = i - linestart; +		if (text[i] == '\0') { +			split_line = 1; +		} +		if (linelen > maxwidth) { +			if (lastspace > linestart+maxwidth/2+6) { +				count -= i-lastspace; +				i = lastspace; +				linelen = i - linestart; +				split_line = 1; +			} else { +				split_line = 1; +			} +		} +		if ((linelen > 0 && split_line) || text[i] == '\n') { +			split_line = 0; +			if (numlines == maxlines) { +				maxlines += 8; +				struct tuple* newlines = (struct tuple*)realloc(lines, sizeof(struct tuple) * maxlines); +				if (!newlines) { +					printf("FATAL: Out of memory\n"); +					return -1; +				} +				lines = newlines; +			} +			lines[numlines].idx = linestart; +			lines[numlines].len = linelen; +			lines[numlines].plen = count; +			if (count > maxlen) maxlen = count; +			numlines++; +			linestart = i+1; +			count = 0; +		} +		else if (text[i] == ' ') { +			lastspace = i; +			count++; +		} else { +			count++; +		} +		i++; +	} +	*lines_out = lines; +	*maxlen_out = maxlen; +	return numlines;  } -void print_progress_bar(double progress) { -#ifndef WIN32 -	if (info_disabled) return; +void set_banner_funcs(void (*showfunc)(const char*), void (*hidefunc)(void)) +{ +	banner_func = showfunc; +	banner_hide_func = hidefunc; +} + +void show_banner(const char* text) +{ +	if (banner_func) { +		banner_func(text); +	} else { +		int i; +		int maxlen = 0; +		struct tuple* lines = NULL; +		int numlines = process_text_lines(text, 74, &lines, &maxlen); +		printf("%.*s\n", maxlen + 4, STARS); +		for (i = 0; i < numlines; i++) { +			printf("* %.*s%.*s *\n", lines[i].len, text + lines[i].idx, maxlen-lines[i].plen, SPACES); +		} +		printf("%.*s\n", maxlen + 4, STARS); +		free(lines); +	} +} + +void hide_banner() +{ +	if (banner_hide_func) { +		banner_hide_func(); +	} +} + +static int (*prompt_func)(const char* title, const char* text) = NULL; + +void set_prompt_func(int (*func)(const char* title, const char* text)) +{ +	prompt_func = func; +} + +int prompt_user(const char* title, const char* text) +{ +	if (!text) return -1; +	if (prompt_func) { +		return prompt_func(title, text); +	} +	int i; +	int result = 0; +	int maxlen = 0; +	struct tuple* lines = NULL; +	int numlines = process_text_lines(text, 74, &lines, &maxlen); +	int outerlen = maxlen+4; +	int titlelen = (title) ? strlen(title) : 0; +	if (titlelen > 0) { +		int lefttitlelen = (titlelen+4)/2; +		int leftpounds = outerlen/2 - lefttitlelen; +		int rightpounds = outerlen-(titlelen+4) - leftpounds; +		printf("%.*s[ %.*s ]%.*s\n", leftpounds, POUNDS, titlelen, title, rightpounds, POUNDS); +	} else { +		printf("%.*s\n", outerlen, POUNDS); +	} +	for (i = 0; i < numlines; i++) { +		printf("%c %.*s%.*s %c\n", *POUNDS, lines[i].len, text + lines[i].idx, maxlen-lines[i].plen, SPACES, *POUNDS); +	} +	free(lines); +	const char* yesmsg = "Type YES and press ENTER to continue, or hit CTRL+C to cancel."; +	int ylen = strlen(yesmsg); +	printf("%c %.*s%.*s %c\n", *POUNDS, ylen, yesmsg, maxlen-ylen, SPACES, *POUNDS); +	printf("%.*s\n", outerlen, POUNDS); + +	char input[64]; +	while (1) { +		printf("> "); +		fflush(stdout); +		fflush(stdin); +		input[0] = '\0'; +		get_user_input(input, 63, 0); +		if (global_quit_flag) { +			result = -1; +			break; +		} +		if (*input != '\0' && !strcmp(input, "YES")) { +			result = 1; +			break; +		} else { +			printf("Invalid input. Please type YES or hit CTRL+C to abort.\n"); +			continue; +		} +	} +	return result; +} + +static void (*update_progress_func)(struct progress_info_entry** list, int count) = NULL; +static double progress_granularity = 0.001; + +void set_update_progress_func(void (*func)(struct progress_info_entry** list, int count)) +{ +	update_progress_func = func; +} + +void set_progress_granularity(double granularity) +{ +	progress_granularity = granularity; +} + +mutex_t prog_mutex; +struct collection progress_info; +thread_once_t progress_info_once = THREAD_ONCE_INIT; +static void _init_progress_info(void) +{ +	mutex_init(&prog_mutex); +	collection_init(&progress_info); +} + +uint32_t progress_get_next_tag(void) +{ +	mutex_lock(&prog_mutex); +	uint32_t newtag = ++progress_unique_tag; +	mutex_unlock(&prog_mutex); +	return newtag; +} + +void progress_reset_tag(void) +{ +	progress_unique_tag = 1; +} + +void register_progress(uint32_t tag, const char* label) +{ +	thread_once(&progress_info_once, _init_progress_info); +	if (!label) { +		return; +	} +	mutex_lock(&prog_mutex); +	struct progress_info_entry* found = NULL; +	FOREACH(struct progress_info_entry* e, &progress_info) { +		if (e->tag == tag) { +			found = e; +			break; +		} +	} ENDFOREACH +	if (found) { +		if (strcmp(found->label, label) != 0) { +			free(found->label); +			found->label = strdup(label); +			if (update_progress_func) { +				update_progress_func((struct progress_info_entry**)(&progress_info)->list, progress_info.capacity); +			} else { +				print_progress_bar(found->label, found->progress); +			} +		} +		mutex_unlock(&prog_mutex); +		return; +	} +	struct progress_info_entry* newinfo = (struct progress_info_entry*)calloc(1, sizeof(struct progress_info_entry)); +	if (!newinfo) { +		logger(LL_ERROR, "Out of memory?!\n"); +		exit(1); +	} +	newinfo->tag = tag; +	newinfo->label = strdup(label); +	newinfo->progress = 0; +	collection_add(&progress_info, newinfo); +	if (update_progress_func) { +		update_progress_func((struct progress_info_entry**)(&progress_info)->list, progress_info.capacity); +	} else { +		print_progress_bar(newinfo->label, newinfo->progress); +	} +	mutex_unlock(&prog_mutex); +} + +void finalize_progress(uint32_t tag) +{ +	mutex_lock(&prog_mutex); +	struct progress_info_entry* found = NULL; +	FOREACH(struct progress_info_entry* e, &progress_info) { +		if (e->tag == tag) { +			found = e; +			break; +		} +	} ENDFOREACH +	if (!found) { +		mutex_unlock(&prog_mutex); +		return; +	} +	collection_remove(&progress_info, found); +	free(found->label); +	free(found); +	if (update_progress_func) { +		update_progress_func((struct progress_info_entry**)(&progress_info)->list, progress_info.capacity); +	} +	mutex_unlock(&prog_mutex); +} + +void print_progress_bar(const char* prefix, double progress) +{  	int i = 0; -	if(progress < 0) return; -	if(progress > 100) progress = 100; -	info("\r["); -	for(i = 0; i < 50; i++) { -		if(i < progress / 2) info("="); -		else info(" "); -	} -	info("] %5.1f%%", progress); -	if(progress >= 100) info("\n"); -	fflush((info_stream) ? info_stream : stdout); -#endif +	if (progress < 0) return; +	if (progress > 1) progress = 1; +	if (prefix) { +		printf("\r%s [", prefix); +	} else { +		printf("\r["); +	} +	for (i = 0; i < 50; i++) { +		if (i < (int)(progress*50.0)) printf("="); +		else printf(" "); +	} +	printf("] %5.1f%% ", progress*100.0); +	if (progress >= 1) printf("\n"); +	fflush(stdout); +} + +void set_progress(uint32_t tag, double progress) +{ +	mutex_lock(&prog_mutex); +	struct progress_info_entry* found = NULL; +	FOREACH(struct progress_info_entry* e, &progress_info) { +		if (e->tag == tag) { +			found = e; +			break; +		} +	} ENDFOREACH +	if (!found) { +		mutex_unlock(&prog_mutex); +		return; +	} +	if (progress < 0) progress = 0; +	if (progress > 1.0) progress = 1.0; +	found->progress = progress; +	if ((progress == 0) || (found->progress - found->lastprog >= progress_granularity)) { +		if (update_progress_func) { +			update_progress_func((struct progress_info_entry**)(&progress_info)->list, progress_info.capacity); +		} else { +			print_progress_bar(found->label, found->progress); +		} +		found->lastprog = found->progress; +	} +	mutex_unlock(&prog_mutex);  }  #define GET_RAND(min, max) ((rand() % (max - min)) + min) @@ -467,8 +668,8 @@ void idevicerestore_progress(struct idevicerestore_client_t* client, int step, d  		client->progress_cb(step, progress, client->progress_cb_data);  	} else {  		// we don't want to be too verbose in regular idevicerestore. -		if ((step == RESTORE_STEP_UPLOAD_FS) || (step == RESTORE_STEP_VERIFY_FS) || (step == RESTORE_STEP_FLASH_FW)) { -			print_progress_bar(100.0 * progress); +		if ((step == RESTORE_STEP_UPLOAD_FS) || (step == RESTORE_STEP_VERIFY_FS) || (step == RESTORE_STEP_FLASH_FW) || (step == RESTORE_STEP_UPLOAD_IMG)) { +			print_progress_bar(NULL, progress);  		}  	}  } @@ -557,91 +758,19 @@ void get_user_input(char *buf, int maxlen, int secure)  	buf[len] = 0;  } -uint64_t _plist_dict_get_uint(plist_t dict, const char *key) -{ -	uint64_t uintval = 0; -	char *strval = NULL; -	uint64_t strsz = 0; -	plist_t node = plist_dict_get_item(dict, key); -	if (!node) { -		return (uint64_t)-1LL; -	} -	switch (plist_get_node_type(node)) { -	case PLIST_UINT: -		plist_get_uint_val(node, &uintval); -		break; -	case PLIST_STRING: -		plist_get_string_val(node, &strval); -		if (strval) { -			uintval = strtoull(strval, NULL, 0); -			free(strval); -		} -		break; -	case PLIST_DATA: -		plist_get_data_val(node, &strval, &strsz); -		if (strval) { -			if (strsz == 8) { -				uintval = le64toh(*(uint64_t*)strval); -			} else if (strsz == 4) { -				uintval = le32toh(*(uint32_t*)strval); -			} else if (strsz == 2) { -				uintval = le16toh(*(uint16_t*)strval); -			} else if (strsz == 1) { -				uintval = strval[0]; -			} else { -				error("%s: ERROR: invalid size %" PRIu64 " for data to integer conversion\n", __func__, strsz); -			} -			free(strval); -		} -		break; -	default: -		break; -	} -	return uintval; -} - -uint8_t _plist_dict_get_bool(plist_t dict, const char *key) +const char* path_get_basename(const char* path)  { -	uint8_t bval = 0; -	uint64_t uintval = 0; -	char *strval = NULL; -	uint64_t strsz = 0; -	plist_t node = plist_dict_get_item(dict, key); -	if (!node) { -		return 0; -	} -	switch (plist_get_node_type(node)) { -	case PLIST_BOOLEAN: -		plist_get_bool_val(node, &bval); -		break; -	case PLIST_UINT: -		plist_get_uint_val(node, &uintval); -		bval = (uint8_t)uintval; -		break; -	case PLIST_STRING: -		plist_get_string_val(node, &strval); -		if (strval) { -			if (strcmp(strval, "true")) { -				bval = 1; -			} else if (strcmp(strval, "false")) { -				bval = 0; -			} -			free(strval); -		} -		break; -	case PLIST_DATA: -		plist_get_data_val(node, &strval, &strsz); -		if (strval) { -			if (strsz == 1) { -				bval = strval[0]; -			} else { -				error("%s: ERROR: invalid size %" PRIu64 " for data to boolean conversion\n", __func__, strsz); -			} -			free(strval); +#ifdef WIN32 +	const char *p = path + strlen(path); +	while (p > path) { +		if ((*p == '/') || (*p == '\\')) { +			return p+1;  		} -		break; -	default: -		break; +		p--;  	} -	return bval; +	return p; +#else +	const char *p = strrchr(path, '/'); +	return p ? p + 1 : path; +#endif  } | 
