blob: 95a5f07141d1af867acf1895921123b710e1464e [file] [log] [blame]
preludedrew38058dc2011-01-29 23:30:44 -07001#include <ctype.h>
2#include <errno.h>
3#include <fcntl.h>
4#include <getopt.h>
5#include <limits.h>
6#include <linux/input.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <sys/reboot.h>
11#include <sys/types.h>
12#include <time.h>
13#include <unistd.h>
14
15#include <sys/wait.h>
16#include <sys/limits.h>
17#include <dirent.h>
18#include <sys/stat.h>
19
20#include <signal.h>
21#include <sys/wait.h>
22
23#include "bootloader.h"
24#include "common.h"
25#include "cutils/properties.h"
26#include "firmware.h"
27#include "install.h"
28#include "minui/minui.h"
29#include "minzip/DirUtil.h"
30#include "roots.h"
31#include "recovery_ui.h"
32
33#include "../../external/yaffs2/yaffs2/utils/mkyaffs2image.h"
34#include "../../external/yaffs2/yaffs2/utils/unyaffs.h"
35
36#include "extendedcommands.h"
37#include "nandroid.h"
38#include "mounts.h"
39#include "flashutils/flashutils.h"
40#include "edify/expr.h"
41
42int signature_check_enabled = 1;
43int script_assert_enabled = 1;
44static const char *SDCARD_UPDATE_FILE = "/sdcard/update.zip";
45
46void
47toggle_signature_check()
48{
49 signature_check_enabled = !signature_check_enabled;
50 ui_print("Signature Check: %s\n", signature_check_enabled ? "Enabled" : "Disabled");
51}
52
53void toggle_script_asserts()
54{
55 script_assert_enabled = !script_assert_enabled;
56 ui_print("Script Asserts: %s\n", script_assert_enabled ? "Enabled" : "Disabled");
57}
58
59int install_zip(const char* packagefilepath)
60{
61 ui_print("\n-- Installing: %s\n", packagefilepath);
62 if (device_flash_type() == MTD) {
63 set_sdcard_update_bootloader_message();
64 }
65 int status = install_package(packagefilepath);
66 ui_reset_progress();
67 if (status != INSTALL_SUCCESS) {
68 ui_set_background(BACKGROUND_ICON_ERROR);
69 ui_print("Installation aborted.\n");
70 return 1;
71 }
72 ui_set_background(BACKGROUND_ICON_NONE);
73 ui_print("\nInstall from sdcard complete.\n");
74 return 0;
75}
76
77char* INSTALL_MENU_ITEMS[] = { "apply /sdcard/update.zip",
78 "choose zip from sdcard",
79 "toggle signature verification",
80 "toggle script asserts",
81 NULL };
82#define ITEM_APPLY_SDCARD 0
83#define ITEM_CHOOSE_ZIP 1
84#define ITEM_SIG_CHECK 2
85#define ITEM_ASSERTS 3
86
87void show_install_update_menu()
88{
89 static char* headers[] = { "Apply update from .zip file on SD card",
90 "",
91 NULL
92 };
93 for (;;)
94 {
95 int chosen_item = get_menu_selection(headers, INSTALL_MENU_ITEMS, 0, 0);
96 switch (chosen_item)
97 {
98 case ITEM_ASSERTS:
99 toggle_script_asserts();
100 break;
101 case ITEM_SIG_CHECK:
102 toggle_signature_check();
103 break;
104 case ITEM_APPLY_SDCARD:
105 {
106 if (confirm_selection("Confirm install?", "Yes - Install /sdcard/update.zip"))
107 install_zip(SDCARD_UPDATE_FILE);
108 break;
109 }
110 case ITEM_CHOOSE_ZIP:
111 show_choose_zip_menu();
112 break;
113 default:
114 return;
115 }
116
117 }
118}
119
120void free_string_array(char** array)
121{
122 if (array == NULL)
123 return;
124 char* cursor = array[0];
125 int i = 0;
126 while (cursor != NULL)
127 {
128 free(cursor);
129 cursor = array[++i];
130 }
131 free(array);
132}
133
134char** gather_files(const char* directory, const char* fileExtensionOrDirectory, int* numFiles)
135{
136 char path[PATH_MAX] = "";
137 DIR *dir;
138 struct dirent *de;
139 int total = 0;
140 int i;
141 char** files = NULL;
142 int pass;
143 *numFiles = 0;
144 int dirLen = strlen(directory);
145
146 dir = opendir(directory);
147 if (dir == NULL) {
148 ui_print("Couldn't open directory.\n");
149 return NULL;
150 }
151
152 int extension_length = 0;
153 if (fileExtensionOrDirectory != NULL)
154 extension_length = strlen(fileExtensionOrDirectory);
155
156 int isCounting = 1;
157 i = 0;
158 for (pass = 0; pass < 2; pass++) {
159 while ((de=readdir(dir)) != NULL) {
160 // skip hidden files
161 if (de->d_name[0] == '.')
162 continue;
163
164 // NULL means that we are gathering directories, so skip this
165 if (fileExtensionOrDirectory != NULL)
166 {
167 // make sure that we can have the desired extension (prevent seg fault)
168 if (strlen(de->d_name) < extension_length)
169 continue;
170 // compare the extension
171 if (strcmp(de->d_name + strlen(de->d_name) - extension_length, fileExtensionOrDirectory) != 0)
172 continue;
173 }
174 else
175 {
176 struct stat info;
177 char fullFileName[PATH_MAX];
178 strcpy(fullFileName, directory);
179 strcat(fullFileName, de->d_name);
180 stat(fullFileName, &info);
181 // make sure it is a directory
182 if (!(S_ISDIR(info.st_mode)))
183 continue;
184 }
185
186 if (pass == 0)
187 {
188 total++;
189 continue;
190 }
191
192 files[i] = (char*) malloc(dirLen + strlen(de->d_name) + 2);
193 strcpy(files[i], directory);
194 strcat(files[i], de->d_name);
195 if (fileExtensionOrDirectory == NULL)
196 strcat(files[i], "/");
197 i++;
198 }
199 if (pass == 1)
200 break;
201 if (total == 0)
202 break;
203 rewinddir(dir);
204 *numFiles = total;
205 files = (char**) malloc((total+1)*sizeof(char*));
206 files[total]=NULL;
207 }
208
209 if(closedir(dir) < 0) {
210 LOGE("Failed to close directory.");
211 }
212
213 if (total==0) {
214 return NULL;
215 }
216
217 // sort the result
218 if (files != NULL) {
219 for (i = 0; i < total; i++) {
220 int curMax = -1;
221 int j;
222 for (j = 0; j < total - i; j++) {
223 if (curMax == -1 || strcmp(files[curMax], files[j]) < 0)
224 curMax = j;
225 }
226 char* temp = files[curMax];
227 files[curMax] = files[total - i - 1];
228 files[total - i - 1] = temp;
229 }
230 }
231
232 return files;
233}
234
235// pass in NULL for fileExtensionOrDirectory and you will get a directory chooser
236char* choose_file_menu(const char* directory, const char* fileExtensionOrDirectory, const char* headers[])
237{
238 char path[PATH_MAX] = "";
239 DIR *dir;
240 struct dirent *de;
241 int numFiles = 0;
242 int numDirs = 0;
243 int i;
244 char* return_value = NULL;
245 int dir_len = strlen(directory);
246
247 char** files = gather_files(directory, fileExtensionOrDirectory, &numFiles);
248 char** dirs = NULL;
249 if (fileExtensionOrDirectory != NULL)
250 dirs = gather_files(directory, NULL, &numDirs);
251 int total = numDirs + numFiles;
252 if (total == 0)
253 {
254 ui_print("No files found.\n");
255 }
256 else
257 {
258 char** list = (char**) malloc((total + 1) * sizeof(char*));
259 list[total] = NULL;
260
261
262 for (i = 0 ; i < numDirs; i++)
263 {
264 list[i] = strdup(dirs[i] + dir_len);
265 }
266
267 for (i = 0 ; i < numFiles; i++)
268 {
269 list[numDirs + i] = strdup(files[i] + dir_len);
270 }
271
272 for (;;)
273 {
274 int chosen_item = get_menu_selection(headers, list, 0, 0);
275 if (chosen_item == GO_BACK)
276 break;
277 static char ret[PATH_MAX];
278 if (chosen_item < numDirs)
279 {
280 char* subret = choose_file_menu(dirs[chosen_item], fileExtensionOrDirectory, headers);
281 if (subret != NULL)
282 {
283 strcpy(ret, subret);
284 return_value = ret;
285 break;
286 }
287 continue;
288 }
289 strcpy(ret, files[chosen_item - numDirs]);
290 return_value = ret;
291 break;
292 }
293 free_string_array(list);
294 }
295
296 free_string_array(files);
297 free_string_array(dirs);
298 return return_value;
299}
300
301void show_choose_zip_menu()
302{
303 if (ensure_path_mounted("/sdcard") != 0) {
304 LOGE ("Can't mount /sdcard\n");
305 return;
306 }
307
308 static char* headers[] = { "Choose a zip to apply",
309 "",
310 NULL
311 };
312
313 char* file = choose_file_menu("/sdcard/", ".zip", headers);
314 if (file == NULL)
315 return;
316 static char* confirm_install = "Confirm install?";
317 static char confirm[PATH_MAX];
318 sprintf(confirm, "Yes - Install %s", basename(file));
319 if (confirm_selection(confirm_install, confirm))
320 install_zip(file);
321}
322
323void show_nandroid_restore_menu()
324{
325 if (ensure_path_mounted("/sdcard") != 0) {
326 LOGE ("Can't mount /sdcard\n");
327 return;
328 }
329
330 static char* headers[] = { "Choose an image to restore",
331 "",
332 NULL
333 };
334
335 char* file = choose_file_menu("/sdcard/clockworkmod/backup/", NULL, headers);
336 if (file == NULL)
337 return;
338
339 if (confirm_selection("Confirm restore?", "Yes - Restore"))
340 nandroid_restore(file, 1, 1, 1, 1, 1, 0);
341}
342
343void show_mount_usb_storage_menu()
344{
345 int fd;
346 Volume *vol = volume_for_path("/sdcard");
347 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file",
348 O_WRONLY)) < 0) {
349 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
350 return -1;
351 }
352
353 if (write(fd, vol->device, strlen(vol->device)) < 0) {
354 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
355 close(fd);
356 return -1;
357 }
358 static char* headers[] = { "USB Mass Storage device",
359 "Leaving this menu unmount",
360 "your SD card from your PC.",
361 "",
362 NULL
363 };
364
365 static char* list[] = { "Unmount", NULL };
366
367 for (;;)
368 {
369 int chosen_item = get_menu_selection(headers, list, 0, 0);
370 if (chosen_item == GO_BACK || chosen_item == 0)
371 break;
372 }
373
374 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file", O_WRONLY)) < 0) {
375 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
376 return -1;
377 }
378
379 char ch = 0;
380 if (write(fd, &ch, 1) < 0) {
381 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
382 close(fd);
383 return -1;
384 }
385}
386
387int confirm_selection(const char* title, const char* confirm)
388{
389 struct stat info;
390 if (0 == stat("/sdcard/clockworkmod/.no_confirm", &info))
391 return 1;
392
393 char* confirm_headers[] = { title, " THIS CAN NOT BE UNDONE.", "", NULL };
394 char* items[] = { "No",
395 "No",
396 "No",
397 "No",
398 "No",
399 "No",
400 "No",
401 confirm, //" Yes -- wipe partition", // [7
402 "No",
403 "No",
404 "No",
405 NULL };
406
407 int chosen_item = get_menu_selection(confirm_headers, items, 0, 0);
408 return chosen_item == 7;
409}
410
411#define MKE2FS_BIN "/sbin/mke2fs"
412#define TUNE2FS_BIN "/sbin/tune2fs"
413#define E2FSCK_BIN "/sbin/e2fsck"
414
415int format_unknown_device(const char *device, const char* path, const char *fs_type)
416{
417 LOGI("Formatting unknown device.\n");
418
419 // device may simply be a name, like "system"
420 if (device[0] != '/')
421 return erase_raw_partition(device);
422
423 // if this is SDEXT:, don't worry about it if it does not exist.
424 if (0 == strcmp(path, "/sd-ext"))
425 {
426 struct stat st;
427 Volume *vol = volume_for_path("/sd-ext");
428 if (vol == NULL || 0 != stat(vol->device, &st))
429 {
430 ui_print("No app2sd partition found. Skipping format of /sd-ext.\n");
431 return 0;
432 }
433 }
434
435 if (NULL != fs_type) {
436 if (strcmp("ext3", fs_type) == 0) {
437 LOGI("Formatting ext3 device.\n");
438 if (0 != ensure_path_unmounted(path)) {
439 LOGE("Error while unmounting %s.\n", path);
440 return -12;
441 }
442 return format_ext3_device(device);
443 }
444
445 if (strcmp("ext2", fs_type) == 0) {
446 LOGI("Formatting ext2 device.\n");
447 if (0 != ensure_path_unmounted(path)) {
448 LOGE("Error while unmounting %s.\n", path);
449 return -12;
450 }
451 return format_ext2_device(device);
452 }
453 }
454
455 if (0 != ensure_path_mounted(path))
456 {
457 ui_print("Error mounting %s!\n", path);
458 ui_print("Skipping format...\n");
459 return 0;
460 }
461
462 static char tmp[PATH_MAX];
463 sprintf(tmp, "rm -rf %s/*", path);
464 __system(tmp);
465 sprintf(tmp, "rm -rf %s/.*", path);
466 __system(tmp);
467
468 ensure_path_unmounted(path);
469 return 0;
470}
471
472//#define MOUNTABLE_COUNT 5
473//#define DEVICE_COUNT 4
474//#define MMC_COUNT 2
475
476void show_partition_menu()
477{
478 static char* headers[] = { "Mounts and Storage Menu",
479 "",
480 NULL
481 };
482
483 typedef char* string;
484 string mounts[][3] = {
485 { "mount /system", "unmount /system", "/system" },
486 { "mount /data", "unmount /data", "/data" },
487 { "mount /cache", "unmount /cache", "/cache" },
488 { "mount /sdcard", "unmount /sdcard", "/sdcard" },
489#ifdef BOARD_HAS_SDCARD_INTERNAL
490 { "mount /emmc", "unmount /emmc", "/emmc" },
491#endif
492 { "mount /sd-ext", "unmount /sd-ext", "/sd-ext" }
493 };
494
495 string devices[][2] = {
496 { "format boot", "/boot" },
497 { "format system", "/system" },
498 { "format data", "/data" },
499 { "format cache", "/cache" },
500 { "format sdcard", "/sdcard" },
501 { "format sd-ext", "/sd-ext" },
502#ifdef BOARD_HAS_SDCARD_INTERNAL
503 { "format internal sdcard", "/emmc" }
504#endif
505 };
506
507 const int MOUNTABLE_COUNT = sizeof(mounts) / sizeof(string) / 3;
508 const int DEVICE_COUNT = sizeof(devices) / sizeof(string) / 2;
509
510 static char* confirm_format = "Confirm format?";
511 static char* confirm = "Yes - Format";
512
513 for (;;)
514 {
515 int ismounted[MOUNTABLE_COUNT];
516 int i;
517 static string options[MOUNTABLE_COUNT + DEVICE_COUNT + 1 + 1]; // mountables, format mtds, format mmcs, usb storage, null
518 for (i = 0; i < MOUNTABLE_COUNT; i++)
519 {
520 ismounted[i] = is_path_mounted(mounts[i][2]);
521 options[i] = ismounted[i] ? mounts[i][1] : mounts[i][0];
522 }
523
524 for (i = 0; i < DEVICE_COUNT; i++)
525 {
526 options[MOUNTABLE_COUNT + i] = devices[i][0];
527 }
528
529 options[MOUNTABLE_COUNT + DEVICE_COUNT] = "mount USB storage";
530 options[MOUNTABLE_COUNT + DEVICE_COUNT + 1] = NULL;
531
532 int chosen_item = get_menu_selection(headers, options, 0, 0);
533 if (chosen_item == GO_BACK)
534 break;
535 if (chosen_item == MOUNTABLE_COUNT + DEVICE_COUNT)
536 {
537 show_mount_usb_storage_menu();
538 }
539 else if (chosen_item < MOUNTABLE_COUNT)
540 {
541 if (ismounted[chosen_item])
542 {
543 if (0 != ensure_path_unmounted(mounts[chosen_item][2]))
544 ui_print("Error unmounting %s!\n", mounts[chosen_item][2]);
545 }
546 else
547 {
548 if (0 != ensure_path_mounted(mounts[chosen_item][2]))
549 ui_print("Error mounting %s!\n", mounts[chosen_item][2]);
550 }
551 }
552 else if (chosen_item < MOUNTABLE_COUNT + DEVICE_COUNT)
553 {
554 chosen_item = chosen_item - MOUNTABLE_COUNT;
555 if (!confirm_selection(confirm_format, confirm))
556 continue;
557 ui_print("Formatting %s...\n", devices[chosen_item][1]);
558 if (0 != format_volume(devices[chosen_item][1]))
559 ui_print("Error formatting %s!\n", devices[chosen_item][1]);
560 else
561 ui_print("Done.\n");
562 }
563 }
564}
565
566#define EXTENDEDCOMMAND_SCRIPT "/cache/recovery/extendedcommand"
567
568int extendedcommand_file_exists()
569{
570 struct stat file_info;
571 return 0 == stat(EXTENDEDCOMMAND_SCRIPT, &file_info);
572}
573
574int edify_main(int argc, char** argv) {
575 load_volume_table();
576 process_volumes();
577 RegisterBuiltins();
578 RegisterRecoveryHooks();
579 FinishRegistration();
580
581 if (argc != 2) {
582 printf("edify <filename>\n");
583 return 1;
584 }
585
586 FILE* f = fopen(argv[1], "r");
587 if (f == NULL) {
588 printf("%s: %s: No such file or directory\n", argv[0], argv[1]);
589 return 1;
590 }
591 char buffer[8192];
592 int size = fread(buffer, 1, 8191, f);
593 fclose(f);
594 buffer[size] = '\0';
595
596 Expr* root;
597 int error_count = 0;
598 yy_scan_bytes(buffer, size);
599 int error = yyparse(&root, &error_count);
600 printf("parse returned %d; %d errors encountered\n", error, error_count);
601 if (error == 0 || error_count > 0) {
602
603 //ExprDump(0, root, buffer);
604
605 State state;
606 state.cookie = NULL;
607 state.script = buffer;
608 state.errmsg = NULL;
609
610 char* result = Evaluate(&state, root);
611 if (result == NULL) {
612 printf("result was NULL, message is: %s\n",
613 (state.errmsg == NULL ? "(NULL)" : state.errmsg));
614 free(state.errmsg);
615 } else {
616 printf("result is [%s]\n", result);
617 }
618 }
619 return 0;
620}
621
622int run_script(char* filename)
623{
624 struct stat file_info;
625 if (0 != stat(filename, &file_info)) {
626 printf("Error executing stat on file: %s\n", filename);
627 return 1;
628 }
629
630 int script_len = file_info.st_size;
631 char* script_data = (char*)malloc(script_len + 1);
632 FILE *file = fopen(filename, "rb");
633 fread(script_data, script_len, 1, file);
634 // supposedly not necessary, but let's be safe.
635 script_data[script_len] = '\0';
636 fclose(file);
637 LOGI("Running script:\n");
638 LOGI("\n%s\n", script_data);
639
640 int ret = run_script_from_buffer(script_data, script_len, filename);
641 free(script_data);
642 return ret;
643}
644
645int run_and_remove_extendedcommand()
646{
647 char tmp[PATH_MAX];
648 sprintf(tmp, "cp %s /tmp/%s", EXTENDEDCOMMAND_SCRIPT, basename(EXTENDEDCOMMAND_SCRIPT));
649 __system(tmp);
650 remove(EXTENDEDCOMMAND_SCRIPT);
651 int i = 0;
652 for (i = 20; i > 0; i--) {
653 ui_print("Waiting for SD Card to mount (%ds)\n", i);
654 if (ensure_path_mounted("/sdcard") == 0) {
655 ui_print("SD Card mounted...\n");
656 break;
657 }
658 sleep(1);
659 }
660 remove("/sdcard/clockworkmod/.recoverycheckpoint");
661 if (i == 0) {
662 ui_print("Timed out waiting for SD card... continuing anyways.");
663 }
664
665 sprintf(tmp, "/tmp/%s", basename(EXTENDEDCOMMAND_SCRIPT));
666 return run_script(tmp);
667}
668
669void show_nandroid_advanced_restore_menu()
670{
671 if (ensure_path_mounted("/sdcard") != 0) {
672 LOGE ("Can't mount /sdcard\n");
673 return;
674 }
675
676 static char* advancedheaders[] = { "Choose an image to restore",
677 "",
678 "Choose an image to restore",
679 "first. The next menu will",
680 "you more options.",
681 "",
682 NULL
683 };
684
685 char* file = choose_file_menu("/sdcard/clockworkmod/backup/", NULL, advancedheaders);
686 if (file == NULL)
687 return;
688
689 static char* headers[] = { "Nandroid Advanced Restore",
690 "",
691 NULL
692 };
693
694 static char* list[] = { "Restore boot",
695 "Restore system",
696 "Restore data",
697 "Restore cache",
698 "Restore sd-ext",
699 "Restore wimax",
700 NULL
701 };
702
703 char tmp[PATH_MAX];
704 if (0 != get_partition_device("wimax", tmp)) {
705 // disable wimax restore option
706 list[5] = NULL;
707 }
708
709 static char* confirm_restore = "Confirm restore?";
710
711 int chosen_item = get_menu_selection(headers, list, 0, 0);
712 switch (chosen_item)
713 {
714 case 0:
715 if (confirm_selection(confirm_restore, "Yes - Restore boot"))
716 nandroid_restore(file, 1, 0, 0, 0, 0, 0);
717 break;
718 case 1:
719 if (confirm_selection(confirm_restore, "Yes - Restore system"))
720 nandroid_restore(file, 0, 1, 0, 0, 0, 0);
721 break;
722 case 2:
723 if (confirm_selection(confirm_restore, "Yes - Restore data"))
724 nandroid_restore(file, 0, 0, 1, 0, 0, 0);
725 break;
726 case 3:
727 if (confirm_selection(confirm_restore, "Yes - Restore cache"))
728 nandroid_restore(file, 0, 0, 0, 1, 0, 0);
729 break;
730 case 4:
731 if (confirm_selection(confirm_restore, "Yes - Restore sd-ext"))
732 nandroid_restore(file, 0, 0, 0, 0, 1, 0);
733 break;
734 case 5:
735 if (confirm_selection(confirm_restore, "Yes - Restore wimax"))
736 nandroid_restore(file, 0, 0, 0, 0, 0, 1);
737 break;
738 }
739}
740
741void show_nandroid_menu()
742{
743 static char* headers[] = { "Nandroid",
744 "",
745 NULL
746 };
747
748 static char* list[] = { "Backup",
749 "Restore",
750 "Advanced Restore",
751 NULL
752 };
753
754 int chosen_item = get_menu_selection(headers, list, 0, 0);
755 switch (chosen_item)
756 {
757 case 0:
758 {
759 char backup_path[PATH_MAX];
760 time_t t = time(NULL);
761 struct tm *tmp = localtime(&t);
762 if (tmp == NULL)
763 {
764 struct timeval tp;
765 gettimeofday(&tp, NULL);
766 sprintf(backup_path, "/sdcard/clockworkmod/backup/%d", tp.tv_sec);
767 }
768 else
769 {
770 strftime(backup_path, sizeof(backup_path), "/sdcard/clockworkmod/backup/%F.%H.%M.%S", tmp);
771 }
772 nandroid_backup(backup_path);
773 }
774 break;
775 case 1:
776 show_nandroid_restore_menu();
777 break;
778 case 2:
779 show_nandroid_advanced_restore_menu();
780 break;
781 }
782}
783
784void wipe_battery_stats()
785{
786 ensure_path_mounted("/data");
787 remove("/data/system/batterystats.bin");
788 ensure_path_unmounted("/data");
789}
790
791void show_advanced_menu()
792{
793 static char* headers[] = { "Advanced and Debugging Menu",
794 "",
795 NULL
796 };
797
798 static char* list[] = { "Reboot Recovery",
799 "Wipe Dalvik Cache",
800 "Wipe Battery Stats",
801 "Report Error",
802 "Key Test",
803#ifndef BOARD_HAS_SMALL_RECOVERY
804 "Partition SD Card",
805 "Fix Permissions",
806#ifdef BOARD_HAS_SDCARD_INTERNAL
807 "Partition Internal SD Card",
808#endif
809#endif
810 NULL
811 };
812
813 for (;;)
814 {
815 int chosen_item = get_menu_selection(headers, list, 0, 0);
816 if (chosen_item == GO_BACK)
817 break;
818 switch (chosen_item)
819 {
820 case 0:
821 __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, "recovery");
822 break;
823 case 1:
824 {
825 if (0 != ensure_path_mounted("/data"))
826 break;
827 ensure_path_mounted("/sd-ext");
828 ensure_path_mounted("/cache");
829 if (confirm_selection( "Confirm wipe?", "Yes - Wipe Dalvik Cache")) {
830 __system("rm -r /data/dalvik-cache");
831 __system("rm -r /cache/dalvik-cache");
832 __system("rm -r /sd-ext/dalvik-cache");
833 }
834 ensure_path_unmounted("/data");
835 ui_print("Dalvik Cache wiped.\n");
836 break;
837 }
838 case 2:
839 {
840 if (confirm_selection( "Confirm wipe?", "Yes - Wipe Battery Stats"))
841 wipe_battery_stats();
842 break;
843 }
844 case 3:
845 handle_failure(1);
846 break;
847 case 4:
848 {
849 ui_print("Outputting key codes.\n");
850 ui_print("Go back to end debugging.\n");
851 int key;
852 int action;
853 do
854 {
855 key = ui_wait_key();
856 action = device_handle_key(key, 1);
857 ui_print("Key: %d\n", key);
858 }
859 while (action != GO_BACK);
860 break;
861 }
862 case 5:
863 {
864 static char* ext_sizes[] = { "128M",
865 "256M",
866 "512M",
867 "1024M",
868 "2048M",
869 "4096M",
870 NULL };
871
872 static char* swap_sizes[] = { "0M",
873 "32M",
874 "64M",
875 "128M",
876 "256M",
877 NULL };
878
879 static char* ext_headers[] = { "Ext Size", "", NULL };
880 static char* swap_headers[] = { "Swap Size", "", NULL };
881
882 int ext_size = get_menu_selection(ext_headers, ext_sizes, 0, 0);
883 if (ext_size == GO_BACK)
884 continue;
885
886 int swap_size = get_menu_selection(swap_headers, swap_sizes, 0, 0);
887 if (swap_size == GO_BACK)
888 continue;
889
890 char sddevice[256];
891 Volume *vol = volume_for_path("/sdcard");
892 strcpy(sddevice, vol->device);
893 // we only want the mmcblk, not the partition
894 sddevice[strlen("/dev/block/mmcblkX")] = NULL;
895 char cmd[PATH_MAX];
896 setenv("SDPATH", sddevice, 1);
897 sprintf(cmd, "sdparted -es %s -ss %s -efs ext3 -s", ext_sizes[ext_size], swap_sizes[swap_size]);
898 ui_print("Partitioning SD Card... please wait...\n");
899 if (0 == __system(cmd))
900 ui_print("Done!\n");
901 else
902 ui_print("An error occured while partitioning your SD Card. Please see /tmp/recovery.log for more details.\n");
903 break;
904 }
905 case 6:
906 {
907 ensure_path_mounted("/system");
908 ensure_path_mounted("/data");
909 ui_print("Fixing permissions...\n");
910 __system("fix_permissions");
911 ui_print("Done!\n");
912 break;
913 }
914 case 7:
915 {
916 static char* ext_sizes[] = { "128M",
917 "256M",
918 "512M",
919 "1024M",
920 "2048M",
921 "4096M",
922 NULL };
923
924 static char* swap_sizes[] = { "0M",
925 "32M",
926 "64M",
927 "128M",
928 "256M",
929 NULL };
930
931 static char* ext_headers[] = { "Data Size", "", NULL };
932 static char* swap_headers[] = { "Swap Size", "", NULL };
933
934 int ext_size = get_menu_selection(ext_headers, ext_sizes, 0, 0);
935 if (ext_size == GO_BACK)
936 continue;
937
938 int swap_size = 0;
939 if (swap_size == GO_BACK)
940 continue;
941
942 char sddevice[256];
943 Volume *vol = volume_for_path("/emmc");
944 strcpy(sddevice, vol->device);
945 // we only want the mmcblk, not the partition
946 sddevice[strlen("/dev/block/mmcblkX")] = NULL;
947 char cmd[PATH_MAX];
948 setenv("SDPATH", sddevice, 1);
949 sprintf(cmd, "sdparted -es %s -ss %s -efs ext3 -s", ext_sizes[ext_size], swap_sizes[swap_size]);
950 ui_print("Partitioning Internal SD Card... please wait...\n");
951 if (0 == __system(cmd))
952 ui_print("Done!\n");
953 else
954 ui_print("An error occured while partitioning your Internal SD Card. Please see /tmp/recovery.log for more details.\n");
955 break;
956 }
957 }
958 }
959}
960
961void write_fstab_root(char *path, FILE *file)
962{
963 Volume *vol = volume_for_path(path);
964 if (vol == NULL) {
965 LOGW("Unable to get recovery.fstab info for %s during fstab generation!\n", path);
966 return;
967 }
968
969 char device[200];
970 if (vol->device[0] != '/')
971 get_partition_device(vol->device, device);
972 else
973 strcpy(device, vol->device);
974
975 fprintf(file, "%s ", device);
976 fprintf(file, "%s ", path);
977 fprintf(file, "%s rw\n", vol->fs_type);
978}
979
980void create_fstab()
981{
982 struct stat info;
983 __system("touch /etc/mtab");
984 FILE *file = fopen("/etc/fstab", "w");
985 if (file == NULL) {
986 LOGW("Unable to create /etc/fstab!\n");
987 return;
988 }
989 write_fstab_root("/cache", file);
990 write_fstab_root("/data", file);
991 if (has_datadata()) {
992 write_fstab_root("/datadata", file);
993 }
994 write_fstab_root("/system", file);
995 write_fstab_root("/sdcard", file);
996 write_fstab_root("/sd-ext", file);
997 fclose(file);
998 LOGI("Completed outputting fstab.\n");
999}
1000
1001int bml_check_volume(const char *path) {
1002 ui_print("Checking %s...\n", path);
1003 ensure_path_unmounted(path);
1004 if (0 == ensure_path_mounted(path)) {
1005 ensure_path_unmounted(path);
1006 return 0;
1007 }
1008
1009 Volume *vol = volume_for_path(path);
1010 if (vol == NULL) {
1011 LOGE("Unable process volume! Skipping...\n");
1012 return 0;
1013 }
1014
1015 ui_print("%s may be rfs. Checking...\n", path);
1016 char tmp[PATH_MAX];
1017 sprintf(tmp, "mount -t rfs %s %s", vol->device, path);
1018 int ret = __system(tmp);
1019 printf("%d\n", ret);
1020 return ret == 0 ? 1 : 0;
1021}
1022
1023void process_volumes() {
1024 create_fstab();
1025
1026 if (device_flash_type() != BML)
1027 return;
1028
1029 ui_print("Checking for ext4 partitions...\n");
1030 int ret = 0;
1031 ret = bml_check_volume("/system");
1032 ret |= bml_check_volume("/data");
1033 if (has_datadata())
1034 ret |= bml_check_volume("/datadata");
1035 ret |= bml_check_volume("/cache");
1036
1037 if (ret == 0) {
1038 ui_print("Done!\n");
1039 return;
1040 }
1041
1042 char backup_path[PATH_MAX];
1043 time_t t = time(NULL);
1044 char backup_name[PATH_MAX];
1045 struct timeval tp;
1046 gettimeofday(&tp, NULL);
1047 sprintf(backup_name, "before-ext4-convert-%d", tp.tv_sec);
1048 sprintf(backup_path, "/sdcard/clockworkmod/backup/%s", backup_name);
1049
1050 ui_set_show_text(1);
1051 ui_print("Filesystems need to be converted to ext4.\n");
1052 ui_print("A backup and restore will now take place.\n");
1053 ui_print("If anything goes wrong, your backup will be\n");
1054 ui_print("named %s. Try restoring it\n", backup_name);
1055 ui_print("in case of error.\n");
1056
1057 nandroid_backup(backup_path);
1058 nandroid_restore(backup_path, 1, 1, 1, 1, 1, 0);
1059 ui_set_show_text(0);
1060}
1061
1062void handle_failure(int ret)
1063{
1064 if (ret == 0)
1065 return;
1066 if (0 != ensure_path_mounted("/sdcard"))
1067 return;
1068 mkdir("/sdcard/clockworkmod", S_IRWXU);
1069 __system("cp /tmp/recovery.log /sdcard/clockworkmod/recovery.log");
1070 ui_print("/tmp/recovery.log was copied to /sdcard/clockworkmod/recovery.log. Please open ROM Manager to report the issue.\n");
1071}
1072
1073int is_path_mounted(const char* path) {
1074 Volume* v = volume_for_path(path);
1075 if (v == NULL) {
1076 return 0;
1077 }
1078 if (strcmp(v->fs_type, "ramdisk") == 0) {
1079 // the ramdisk is always mounted.
1080 return 1;
1081 }
1082
1083 int result;
1084 result = scan_mounted_volumes();
1085 if (result < 0) {
1086 LOGE("failed to scan mounted volumes\n");
1087 return 0;
1088 }
1089
1090 const MountedVolume* mv =
1091 find_mounted_volume_by_mount_point(v->mount_point);
1092 if (mv) {
1093 // volume is already mounted
1094 return 1;
1095 }
1096 return 0;
1097}
1098
1099int has_datadata() {
1100 Volume *vol = volume_for_path("/datadata");
1101 return vol != NULL;
1102}
1103
1104int volume_main(int argc, char **argv) {
1105 load_volume_table();
1106 return 0;
1107}
1108
1109void handle_chargemode() {
1110 const char* filename = "/proc/cmdline";
1111 struct stat file_info;
1112 if (0 != stat(filename, &file_info))
1113 return;
1114
1115 int file_len = file_info.st_size;
1116 char* file_data = (char*)malloc(file_len + 1);
1117 FILE *file = fopen(filename, "rb");
1118 if (file == NULL)
1119 return;
1120 fread(file_data, file_len, 1, file);
1121 // supposedly not necessary, but let's be safe.
1122 file_data[file_len] = '\0';
1123 fclose(file);
1124
1125 if (strstr(file_data, "androidboot.mode=offmode_charging") != NULL)
1126 reboot(RB_POWER_OFF);
1127 }