summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--TODO25
-rw-r--r--include/libirecovery.h5
-rw-r--r--scripts/test.irs21
-rw-r--r--src/irecovery.c42
-rw-r--r--src/libirecovery.c142
5 files changed, 184 insertions, 51 deletions
diff --git a/TODO b/TODO
index 306a1ae..411f6e6 100644
--- a/TODO
+++ b/TODO
@@ -1,16 +1,15 @@
1TODO List 1TODO List
2------------------------------------------------ 2------------------------------------------------
3 3
41) libirecovery debug should be as static variable so the client doesn't need to be passed and can be set only once. 4o) Need to implement irecv_saveenv()
52) Need to implement irecv_saveenv() 5o) Need to implement irecv_bootx()
63) Need to implement irecv_bootx() 6o) Neex to implement irecv_go()
74) Neex to implement irecv_go() 7o) Need to implement irecv_bgcolor()
85) Need to implement irecv_bgcolor() 8o) Need to implememt irecv_setpicture()
96) Need to implememt irecv_setpicture() 9o) Need to impelemnt irecv_reboot()
107) Need to impelemnt irecv_reboot() 10o) Should figure out a better place to store callbacks so the CONNECTED callback can actually be used
118) Should figure out a better place to store callbacks so the CONNECTED callback can actually be used 11o) would be nice to change to use asyncronous connections
129) would be nice to change to use asyncronous connections 12o) could add a function to identify whether we're connected to iBoot/iBEC/iBSS or DFU
1310) could add a function to identify whether we're connected to iBoot/iBEC/iBSS or DFU 13o) could add a function to identify which version we're connected to
1411) could add a function to identify which version we're connected to 14o) could add a function to return the device serial number
1512) could add a function to return the device serial number 15o) fix command parsing to strip quotes \ No newline at end of file
1613) fix command parsing to strip quotes \ No newline at end of file
diff --git a/include/libirecovery.h b/include/libirecovery.h
index 50ec5be..d30dd73 100644
--- a/include/libirecovery.h
+++ b/include/libirecovery.h
@@ -71,7 +71,6 @@ struct irecv_client {
71 int interface; 71 int interface;
72 int alt_interface; 72 int alt_interface;
73 unsigned short mode; 73 unsigned short mode;
74 libusb_context* context;
75 libusb_device_handle* handle; 74 libusb_device_handle* handle;
76 irecv_event_cb_t progress_callback; 75 irecv_event_cb_t progress_callback;
77 irecv_event_cb_t received_callback; 76 irecv_event_cb_t received_callback;
@@ -89,12 +88,12 @@ irecv_error_t irecv_reset(irecv_client_t client);
89irecv_error_t irecv_close(irecv_client_t client); 88irecv_error_t irecv_close(irecv_client_t client);
90irecv_error_t irecv_receive(irecv_client_t client); 89irecv_error_t irecv_receive(irecv_client_t client);
91irecv_error_t irecv_send_exploit(irecv_client_t client); 90irecv_error_t irecv_send_exploit(irecv_client_t client);
92irecv_error_t irecv_set_debug(irecv_client_t client, int level); 91void irecv_set_debug_level(int level);
92irecv_error_t irecv_execute_script(irecv_client_t client, const char* filename);
93irecv_error_t irecv_getenv(irecv_client_t client, const char* variable, char** value); 93irecv_error_t irecv_getenv(irecv_client_t client, const char* variable, char** value);
94irecv_error_t irecv_get_cpid(irecv_client_t client, unsigned int* cpid); 94irecv_error_t irecv_get_cpid(irecv_client_t client, unsigned int* cpid);
95irecv_error_t irecv_get_bdid(irecv_client_t client, unsigned int* bdid); 95irecv_error_t irecv_get_bdid(irecv_client_t client, unsigned int* bdid);
96irecv_error_t irecv_get_ecid(irecv_client_t client, unsigned long long* ecid); 96irecv_error_t irecv_get_ecid(irecv_client_t client, unsigned long long* ecid);
97irecv_error_t irecv_send(irecv_client_t client, unsigned char* command);
98irecv_error_t irecv_send_file(irecv_client_t client, const char* filename); 97irecv_error_t irecv_send_file(irecv_client_t client, const char* filename);
99irecv_error_t irecv_send_command(irecv_client_t client, unsigned char* command); 98irecv_error_t irecv_send_command(irecv_client_t client, unsigned char* command);
100irecv_error_t irecv_set_configuration(irecv_client_t client, int configuration); 99irecv_error_t irecv_set_configuration(irecv_client_t client, int configuration);
diff --git a/scripts/test.irs b/scripts/test.irs
new file mode 100644
index 0000000..77f959d
--- /dev/null
+++ b/scripts/test.irs
@@ -0,0 +1,21 @@
1# This small script should make the device flash
2# Red, Green, Blue a few times then reboot.
3bgcolor 255 0 0
4bgcolor 0 255 0
5bgcolor 0 0 255
6bgcolor 255 0 0
7bgcolor 0 255 0
8bgcolor 0 0 255
9bgcolor 255 0 0
10bgcolor 0 255 0
11bgcolor 0 0 255
12bgcolor 255 0 0
13bgcolor 0 255 0
14bgcolor 0 0 255
15bgcolor 255 0 0
16bgcolor 0 255 0
17bgcolor 0 0 255
18bgcolor 255 0 0
19bgcolor 0 255 0
20bgcolor 0 0 255
21reboot
diff --git a/src/irecovery.c b/src/irecovery.c
index baae17e..c282cda 100644
--- a/src/irecovery.c
+++ b/src/irecovery.c
@@ -27,13 +27,13 @@
27#define debug(...) if(verbose) fprintf(stderr, __VA_ARGS__) 27#define debug(...) if(verbose) fprintf(stderr, __VA_ARGS__)
28 28
29enum { 29enum {
30 kResetDevice, kStartShell, kSendCommand, kSendFile, kSendExploit 30 kResetDevice, kStartShell, kSendCommand, kSendFile, kSendExploit, kSendScript
31}; 31};
32 32
33static unsigned int quit = 0; 33static unsigned int quit = 0;
34static unsigned int verbose = 0; 34static unsigned int verbose = 0;
35 35
36void print_progress_bar(const char* operation, double progress); 36void print_progress_bar(double progress);
37int received_cb(irecv_client_t client, const irecv_event_t* event); 37int received_cb(irecv_client_t client, const irecv_event_t* event);
38int progress_cb(irecv_client_t client, const irecv_event_t* event); 38int progress_cb(irecv_client_t client, const irecv_event_t* event);
39int precommand_cb(irecv_client_t client, const irecv_event_t* event); 39int precommand_cb(irecv_client_t client, const irecv_event_t* event);
@@ -61,7 +61,7 @@ void parse_command(irecv_client_t client, unsigned char* command, unsigned int s
61 61
62 if (!strcmp(cmd, "/upload")) { 62 if (!strcmp(cmd, "/upload")) {
63 char* filename = strtok(NULL, " "); 63 char* filename = strtok(NULL, " ");
64 debug("Sending %s\n", filename); 64 debug("Uploading files %s\n", filename);
65 if (filename != NULL) { 65 if (filename != NULL) {
66 irecv_send_file(client, filename); 66 irecv_send_file(client, filename);
67 } 67 }
@@ -69,12 +69,21 @@ void parse_command(irecv_client_t client, unsigned char* command, unsigned int s
69 69
70 if (!strcmp(cmd, "/exploit")) { 70 if (!strcmp(cmd, "/exploit")) {
71 char* filename = strtok(NULL, " "); 71 char* filename = strtok(NULL, " ");
72 debug("Sending %s\n", filename); 72 debug("Sending exploit %s\n", filename);
73 if (filename != NULL) { 73 if (filename != NULL) {
74 irecv_send_file(client, filename); 74 irecv_send_file(client, filename);
75 } 75 }
76 irecv_send_exploit(client); 76 irecv_send_exploit(client);
77 } 77 } else
78
79 if (!strcmp(cmd, "/execute")) {
80 char* filename = strtok(NULL, " ");
81 debug("Executing script %s\n", filename);
82 if (filename != NULL) {
83 irecv_execute_script(client, filename);
84 }
85 }
86
78 87
79 free(action); 88 free(action);
80} 89}
@@ -171,12 +180,12 @@ int postcommand_cb(irecv_client_t client, const irecv_event_t* event) {
171 180
172int progress_cb(irecv_client_t client, const irecv_event_t* event) { 181int progress_cb(irecv_client_t client, const irecv_event_t* event) {
173 if (event->type == IRECV_PROGRESS) { 182 if (event->type == IRECV_PROGRESS) {
174 print_progress_bar(event->data, event->progress); 183 print_progress_bar(event->progress);
175 } 184 }
176 return 0; 185 return 0;
177} 186}
178 187
179void print_progress_bar(const char* operation, double progress) { 188void print_progress_bar(double progress) {
180 int i = 0; 189 int i = 0;
181 if(progress < 0) { 190 if(progress < 0) {
182 return; 191 return;
@@ -186,7 +195,7 @@ void print_progress_bar(const char* operation, double progress) {
186 progress = 100; 195 progress = 100;
187 } 196 }
188 197
189 printf("\r%s [", operation); 198 printf("\r[");
190 for(i = 0; i < 50; i++) { 199 for(i = 0; i < 50; i++) {
191 if(i < progress / 2) { 200 if(i < progress / 2) {
192 printf("="); 201 printf("=");
@@ -212,6 +221,7 @@ void print_usage() {
212 printf("\t-h\t\tShow this help.\n"); 221 printf("\t-h\t\tShow this help.\n");
213 printf("\t-r\t\tReset client.\n"); 222 printf("\t-r\t\tReset client.\n");
214 printf("\t-s\t\tStart interactive shell.\n"); 223 printf("\t-s\t\tStart interactive shell.\n");
224 printf("\t-e <script>\tExecutes recovery shell script.");
215 exit(1); 225 exit(1);
216} 226}
217 227
@@ -222,7 +232,7 @@ int main(int argc, char** argv) {
222 char* argument = NULL; 232 char* argument = NULL;
223 irecv_error_t error = 0; 233 irecv_error_t error = 0;
224 if (argc == 1) print_usage(); 234 if (argc == 1) print_usage();
225 while ((opt = getopt(argc, argv, "vhrsc:f:k::")) > 0) { 235 while ((opt = getopt(argc, argv, "vhrsc:f:e:k::")) > 0) {
226 switch (opt) { 236 switch (opt) {
227 case 'v': 237 case 'v':
228 verbose += 1; 238 verbose += 1;
@@ -255,6 +265,11 @@ int main(int argc, char** argv) {
255 argument = optarg; 265 argument = optarg;
256 break; 266 break;
257 267
268 case 'e':
269 action = kSendScript;
270 argument = optarg;
271 break;
272
258 default: 273 default:
259 fprintf(stderr, "Unknown argument\n"); 274 fprintf(stderr, "Unknown argument\n");
260 return -1; 275 return -1;
@@ -275,7 +290,7 @@ int main(int argc, char** argv) {
275 } 290 }
276 } 291 }
277 292
278 if (verbose) irecv_set_debug(client, verbose); 293 if (verbose) irecv_set_debug_level(verbose);
279 294
280 switch (action) { 295 switch (action) {
281 case kResetDevice: 296 case kResetDevice:
@@ -310,6 +325,13 @@ int main(int argc, char** argv) {
310 init_shell(client); 325 init_shell(client);
311 break; 326 break;
312 327
328 case kSendScript:
329 error = irecv_execute_script(client, argument);
330 if(error != IRECV_E_SUCCESS) {
331 debug("%s\n", irecv_strerror(error));
332 }
333 break;
334
313 default: 335 default:
314 fprintf(stderr, "Unknown action\n"); 336 fprintf(stderr, "Unknown action\n");
315 break; 337 break;
diff --git a/src/libirecovery.c b/src/libirecovery.c
index 05a162f..dd5c734 100644
--- a/src/libirecovery.c
+++ b/src/libirecovery.c
@@ -25,23 +25,30 @@
25#include "libirecovery.h" 25#include "libirecovery.h"
26 26
27#define BUFFER_SIZE 0x1000 27#define BUFFER_SIZE 0x1000
28#define debug(...) if(client->debug) fprintf(stderr, __VA_ARGS__) 28#define debug(...) if(libirecovery_debug) fprintf(stderr, __VA_ARGS__)
29 29
30void irecv_print_progress(const char* operation, float progress); 30static int libirecovery_debug = 0;
31static libusb_context* libirecovery_context = NULL;
32
33int irecv_write_file(const char* filename, const void* data, size_t size);
34int irecv_read_file(const char* filename, char** data, uint32_t* size);
31 35
32irecv_error_t irecv_open(irecv_client_t* pclient) { 36irecv_error_t irecv_open(irecv_client_t* pclient) {
33 int i = 0; 37 int i = 0;
34 char serial[256]; 38 char serial[256];
35 struct libusb_device* usb_device = NULL; 39 struct libusb_device* usb_device = NULL;
36 struct libusb_context* usb_context = NULL;
37 struct libusb_device** usb_device_list = NULL; 40 struct libusb_device** usb_device_list = NULL;
38 struct libusb_device_handle* usb_handle = NULL; 41 struct libusb_device_handle* usb_handle = NULL;
39 struct libusb_device_descriptor usb_descriptor; 42 struct libusb_device_descriptor usb_descriptor;
40 43
41 *pclient = NULL; 44 *pclient = NULL;
42 libusb_init(&usb_context); 45 libusb_init(&libirecovery_context);
46 if(libirecovery_debug) {
47 irecv_set_debug_level(libirecovery_debug);
48 }
49
43 irecv_error_t error = IRECV_E_SUCCESS; 50 irecv_error_t error = IRECV_E_SUCCESS;
44 int usb_device_count = libusb_get_device_list(usb_context, &usb_device_list); 51 int usb_device_count = libusb_get_device_list(libirecovery_context, &usb_device_list);
45 for (i = 0; i < usb_device_count; i++) { 52 for (i = 0; i < usb_device_count; i++) {
46 usb_device = usb_device_list[i]; 53 usb_device = usb_device_list[i];
47 libusb_get_device_descriptor(usb_device, &usb_descriptor); 54 libusb_get_device_descriptor(usb_device, &usb_descriptor);
@@ -57,7 +64,7 @@ irecv_error_t irecv_open(irecv_client_t* pclient) {
57 if (usb_handle == NULL) { 64 if (usb_handle == NULL) {
58 libusb_free_device_list(usb_device_list, 1); 65 libusb_free_device_list(usb_device_list, 1);
59 libusb_close(usb_handle); 66 libusb_close(usb_handle);
60 libusb_exit(usb_context); 67 libusb_exit(libirecovery_context);
61 return IRECV_E_UNABLE_TO_CONNECT; 68 return IRECV_E_UNABLE_TO_CONNECT;
62 } 69 }
63 libusb_free_device_list(usb_device_list, 1); 70 libusb_free_device_list(usb_device_list, 1);
@@ -65,14 +72,13 @@ irecv_error_t irecv_open(irecv_client_t* pclient) {
65 irecv_client_t client = (irecv_client_t) malloc(sizeof(struct irecv_client)); 72 irecv_client_t client = (irecv_client_t) malloc(sizeof(struct irecv_client));
66 if (client == NULL) { 73 if (client == NULL) {
67 libusb_close(usb_handle); 74 libusb_close(usb_handle);
68 libusb_exit(usb_context); 75 libusb_exit(libirecovery_context);
69 return IRECV_E_OUT_OF_MEMORY; 76 return IRECV_E_OUT_OF_MEMORY;
70 } 77 }
71 78
72 memset(client, '\0', sizeof(struct irecv_client)); 79 memset(client, '\0', sizeof(struct irecv_client));
73 client->interface = 0; 80 client->interface = 0;
74 client->handle = usb_handle; 81 client->handle = usb_handle;
75 client->context = usb_context;
76 client->mode = usb_descriptor.idProduct; 82 client->mode = usb_descriptor.idProduct;
77 83
78 error = irecv_set_configuration(client, 1); 84 error = irecv_set_configuration(client, 1);
@@ -223,9 +229,9 @@ irecv_error_t irecv_close(irecv_client_t client) {
223 client->handle = NULL; 229 client->handle = NULL;
224 } 230 }
225 231
226 if (client->context != NULL) { 232 if (libirecovery_context != NULL) {
227 libusb_exit(client->context); 233 libusb_exit(libirecovery_context);
228 client->context = NULL; 234 libirecovery_context = NULL;
229 } 235 }
230 236
231 free(client); 237 free(client);
@@ -235,14 +241,11 @@ irecv_error_t irecv_close(irecv_client_t client) {
235 return IRECV_E_SUCCESS; 241 return IRECV_E_SUCCESS;
236} 242}
237 243
238irecv_error_t irecv_set_debug(irecv_client_t client, int level) { 244void irecv_set_debug_level(int level) {
239 if (client == NULL || client->context == NULL) { 245 libirecovery_debug = level;
240 return IRECV_E_NO_DEVICE; 246 if(libirecovery_context) {
247 libusb_set_debug(libirecovery_context, libirecovery_debug);
241 } 248 }
242
243 libusb_set_debug(client->context, level);
244 client->debug = level;
245 return IRECV_E_SUCCESS;
246} 249}
247 250
248irecv_error_t irecv_send_command(irecv_client_t client, unsigned char* command) { 251irecv_error_t irecv_send_command(irecv_client_t client, unsigned char* command) {
@@ -350,14 +353,11 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un
350 unsigned int status = 0; 353 unsigned int status = 0;
351 for (i = 0; i < packets; i++) { 354 for (i = 0; i < packets; i++) {
352 int size = i + 1 < packets ? 0x800 : last; 355 int size = i + 1 < packets ? 0x800 : last;
353 int bytes = libusb_control_transfer(client->handle, 0x21, 1, 0, 0, &buffer[i * 0x800], 356 int bytes = libusb_control_transfer(client->handle, 0x21, 1, 0, 0, &buffer[i * 0x800], size, 1000);
354 size, 1000);
355 if (bytes != size) { 357 if (bytes != size) {
356 return IRECV_E_USB_UPLOAD; 358 return IRECV_E_USB_UPLOAD;
357 } 359 }
358 360
359 debug("Sent %d bytes\n", bytes);
360
361 error = irecv_get_status(client, &status); 361 error = irecv_get_status(client, &status);
362 if (error != IRECV_E_SUCCESS) { 362 if (error != IRECV_E_SUCCESS) {
363 return error; 363 return error;
@@ -375,6 +375,8 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un
375 event.data = "Uploading"; 375 event.data = "Uploading";
376 event.size = count; 376 event.size = count;
377 client->progress_callback(client, &event); 377 client->progress_callback(client, &event);
378 } else {
379 debug("Sent: %d bytes - %d of %d\n", bytes, count, length);
378 } 380 }
379 } 381 }
380 382
@@ -457,7 +459,6 @@ irecv_error_t irecv_get_cpid(irecv_client_t client, unsigned int* cpid) {
457 } 459 }
458 460
459 libusb_get_string_descriptor_ascii(client->handle, 3, info, 255); 461 libusb_get_string_descriptor_ascii(client->handle, 3, info, 255);
460 printf("%d: %s\n", strlen(info), info);
461 462
462 unsigned char* cpid_string = strstr(info, "CPID:"); 463 unsigned char* cpid_string = strstr(info, "CPID:");
463 if (cpid_string == NULL) { 464 if (cpid_string == NULL) {
@@ -478,7 +479,6 @@ irecv_error_t irecv_get_bdid(irecv_client_t client, unsigned int* bdid) {
478 } 479 }
479 480
480 libusb_get_string_descriptor_ascii(client->handle, 3, info, 255); 481 libusb_get_string_descriptor_ascii(client->handle, 3, info, 255);
481 printf("%d: %s\n", strlen(info), info);
482 482
483 unsigned char* bdid_string = strstr(info, "BDID:"); 483 unsigned char* bdid_string = strstr(info, "BDID:");
484 if (bdid_string == NULL) { 484 if (bdid_string == NULL) {
@@ -499,7 +499,6 @@ irecv_error_t irecv_get_ecid(irecv_client_t client, unsigned long long* ecid) {
499 } 499 }
500 500
501 libusb_get_string_descriptor_ascii(client->handle, 3, info, 255); 501 libusb_get_string_descriptor_ascii(client->handle, 3, info, 255);
502 printf("%d: %s\n", strlen(info), info);
503 502
504 unsigned char* ecid_string = strstr(info, "ECID:"); 503 unsigned char* ecid_string = strstr(info, "ECID:");
505 if (ecid_string == NULL) { 504 if (ecid_string == NULL) {
@@ -520,6 +519,37 @@ irecv_error_t irecv_send_exploit(irecv_client_t client) {
520 return IRECV_E_SUCCESS; 519 return IRECV_E_SUCCESS;
521} 520}
522 521
522irecv_error_t irecv_execute_script(irecv_client_t client, const char* filename) {
523 irecv_error_t error = IRECV_E_SUCCESS;
524 if (client == NULL || client->handle == NULL) {
525 return IRECV_E_NO_DEVICE;
526 }
527
528 int file_size = 0;
529 char* file_data = NULL;
530 if(irecv_read_file(filename, &file_data, &file_size) < 0) {
531 return IRECV_E_FILE_NOT_FOUND;
532 }
533
534 char* line = strtok(file_data, "\n");
535 while(line != NULL) {
536 if(line[0] != '#') {
537 error = irecv_send_command(client, line);
538 if(error != IRECV_E_SUCCESS) {
539 return error;
540 }
541
542 error = irecv_receive(client);
543 if(error != IRECV_E_SUCCESS) {
544 return error;
545 }
546 }
547 line = strtok(NULL, "\n");
548 }
549
550 return IRECV_E_SUCCESS;
551}
552
523irecv_error_t irecv_setenv(irecv_client_t client, const char* variable, const char* value) { 553irecv_error_t irecv_setenv(irecv_client_t client, const char* variable, const char* value) {
524 char command[256]; 554 char command[256];
525 if (client == NULL || client->handle == NULL) { 555 if (client == NULL || client->handle == NULL) {
@@ -578,3 +608,65 @@ const char* irecv_strerror(irecv_error_t error) {
578 608
579 return NULL; 609 return NULL;
580} 610}
611
612int irecv_write_file(const char* filename, const void* data, size_t size) {
613 size_t bytes = 0;
614 FILE* file = NULL;
615
616 debug("Writing data to %s\n", filename);
617 file = fopen(filename, "wb");
618 if (file == NULL) {
619 error("read_file: Unable to open file %s\n", filename);
620 return -1;
621 }
622
623 bytes = fwrite(data, 1, size, file);
624 fclose(file);
625
626 if (bytes != size) {
627 error("ERROR: Unable to write entire file: %s: %d of %d\n", filename, bytes, size);
628 return -1;
629 }
630
631 return size;
632}
633
634int irecv_read_file(const char* filename, char** data, uint32_t* size) {
635 size_t bytes = 0;
636 size_t length = 0;
637 FILE* file = NULL;
638 char* buffer = NULL;
639 debug("Reading data from %s\n", filename);
640
641 *size = 0;
642 *data = NULL;
643
644 file = fopen(filename, "rb");
645 if (file == NULL) {
646 error("read_file: File %s not found\n", filename);
647 return -1;
648 }
649
650 fseek(file, 0, SEEK_END);
651 length = ftell(file);
652 rewind(file);
653
654 buffer = (char*) malloc(length);
655 if(buffer == NULL) {
656 error("ERROR: Out of memory\n");
657 fclose(file);
658 return -1;
659 }
660 bytes = fread(buffer, 1, length, file);
661 fclose(file);
662
663 if(bytes != length) {
664 error("ERROR: Unable to read entire file\n");
665 free(buffer);
666 return -1;
667 }
668
669 *size = length;
670 *data = buffer;
671 return 0;
672}