blob: 9310305ce3943a6745163354d8b3d326e557ba93 [file] [log] [blame]
Koushik K. Dutta6060e5c2010-02-11 22:27:06 -08001#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
Koushik K. Duttae9234872010-02-12 00:43:24 -080015#include <sys/wait.h>
16#include <sys/limits.h>
17#include <dirent.h>
Koushik K. Dutta49f56892010-02-25 14:51:05 -080018#include <sys/stat.h>
Koushik K. Duttae9234872010-02-12 00:43:24 -080019
Koushik K. Dutta33370db2010-02-25 11:39:07 -080020#include <signal.h>
21#include <sys/wait.h>
22
Koushik K. Dutta6060e5c2010-02-11 22:27:06 -080023#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
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -080033#include "commands.h"
34#include "amend/amend.h"
35
Koushik Dutta14239d22010-06-14 15:02:48 -070036#include "mtdutils/mtdutils.h"
Koushik K. Duttaa85d7cc2010-03-12 17:00:58 -080037#include "mtdutils/dump_image.h"
38#include "../../external/yaffs2/yaffs2/utils/mkyaffs2image.h"
Koushik K. Dutta54305a82010-03-12 17:43:26 -080039#include "../../external/yaffs2/yaffs2/utils/unyaffs.h"
Koushik K. Duttaa85d7cc2010-03-12 17:00:58 -080040
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -080041#include "extendedcommands.h"
42#include "nandroid.h"
43
Koushik K. Dutta6060e5c2010-02-11 22:27:06 -080044int signature_check_enabled = 1;
45int script_assert_enabled = 1;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080046static const char *SDCARD_PACKAGE_FILE = "SDCARD:update.zip";
Koushik K. Dutta6060e5c2010-02-11 22:27:06 -080047
48void
49toggle_signature_check()
50{
51 signature_check_enabled = !signature_check_enabled;
52 ui_print("Signature Check: %s\n", signature_check_enabled ? "Enabled" : "Disabled");
53}
54
55void toggle_script_asserts()
56{
57 script_assert_enabled = !script_assert_enabled;
Koushik K. Duttae9234872010-02-12 00:43:24 -080058 ui_print("Script Asserts: %s\n", script_assert_enabled ? "Enabled" : "Disabled");
59}
60
Koushik K. Duttaea46fe22010-03-08 02:58:04 -080061int install_zip(const char* packagefilepath)
Koushik K. Duttae9234872010-02-12 00:43:24 -080062{
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080063 ui_print("\n-- Installing: %s\n", packagefilepath);
64 set_sdcard_update_bootloader_message();
65 int status = install_package(packagefilepath);
Koushik K. Duttaf3534d02010-04-18 18:06:24 -070066 ui_reset_progress();
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080067 if (status != INSTALL_SUCCESS) {
68 ui_set_background(BACKGROUND_ICON_ERROR);
69 ui_print("Installation aborted.\n");
Koushik K. Duttaea46fe22010-03-08 02:58:04 -080070 return 1;
Koushik K. Dutta79ce82c2010-02-25 12:03:17 -080071 }
72 if (firmware_update_pending()) {
73 ui_print("\nReboot via menu to complete\ninstallation.\n");
Koushik K. Dutta001c5b52010-02-25 14:53:57 -080074 }
Koushik K. Dutta001c5b52010-02-25 14:53:57 -080075 ui_set_background(BACKGROUND_ICON_NONE);
Koushik K. Dutta99fb6fe2010-03-03 00:42:58 -080076 ui_print("\nInstall from sdcard complete.\n");
Koushik K. Duttaea46fe22010-03-08 02:58:04 -080077 return 0;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080078}
79
80char* INSTALL_MENU_ITEMS[] = { "apply sdcard:update.zip",
81 "choose zip from sdcard",
82 "toggle signature verification",
83 "toggle script asserts",
84 NULL };
85#define ITEM_APPLY_SDCARD 0
86#define ITEM_CHOOSE_ZIP 1
87#define ITEM_SIG_CHECK 2
88#define ITEM_ASSERTS 3
89
90void show_install_update_menu()
91{
92 static char* headers[] = { "Apply update from .zip file on SD card",
93 "",
94 NULL
95 };
96 for (;;)
97 {
98 int chosen_item = get_menu_selection(headers, INSTALL_MENU_ITEMS, 0);
99 switch (chosen_item)
100 {
101 case ITEM_ASSERTS:
102 toggle_script_asserts();
103 break;
104 case ITEM_SIG_CHECK:
105 toggle_signature_check();
106 break;
107 case ITEM_APPLY_SDCARD:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700108 {
109 if (confirm_selection("Confirm install?", "Yes - Install /sdcard/update.zip"))
110 install_zip(SDCARD_PACKAGE_FILE);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800111 break;
Koushik Duttad63eaef2010-07-14 21:01:21 -0700112 }
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800113 case ITEM_CHOOSE_ZIP:
114 show_choose_zip_menu();
115 break;
116 default:
117 return;
118 }
119
120 }
121}
122
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700123void free_string_array(char** array)
124{
125 if (array == NULL)
126 return;
127 char* cursor = array[0];
128 int i = 0;
129 while (cursor != NULL)
130 {
131 free(cursor);
132 cursor = array[++i];
133 }
134 free(array);
135}
136
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800137char** gather_files(const char* directory, const char* fileExtensionOrDirectory, int* numFiles)
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800138{
Koushik K. Duttae9234872010-02-12 00:43:24 -0800139 char path[PATH_MAX] = "";
140 DIR *dir;
141 struct dirent *de;
142 int total = 0;
143 int i;
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800144 char** files = NULL;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800145 int pass;
146 *numFiles = 0;
147 int dirLen = strlen(directory);
Koushik K. Duttae9234872010-02-12 00:43:24 -0800148
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800149 dir = opendir(directory);
150 if (dir == NULL) {
151 ui_print("Couldn't open directory.\n");
152 return NULL;
153 }
154
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800155 int extension_length = 0;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800156 if (fileExtensionOrDirectory != NULL)
157 extension_length = strlen(fileExtensionOrDirectory);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800158
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800159 int isCounting = 1;
160 i = 0;
161 for (pass = 0; pass < 2; pass++) {
162 while ((de=readdir(dir)) != NULL) {
163 // skip hidden files
164 if (de->d_name[0] == '.')
165 continue;
166
167 // NULL means that we are gathering directories, so skip this
168 if (fileExtensionOrDirectory != NULL)
169 {
170 // make sure that we can have the desired extension (prevent seg fault)
171 if (strlen(de->d_name) < extension_length)
172 continue;
173 // compare the extension
174 if (strcmp(de->d_name + strlen(de->d_name) - extension_length, fileExtensionOrDirectory) != 0)
175 continue;
176 }
177 else
178 {
179 struct stat info;
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700180 char fullFileName[PATH_MAX];
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800181 strcpy(fullFileName, directory);
182 strcat(fullFileName, de->d_name);
183 stat(fullFileName, &info);
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800184 // make sure it is a directory
185 if (!(S_ISDIR(info.st_mode)))
186 continue;
187 }
188
189 if (pass == 0)
190 {
191 total++;
192 continue;
193 }
194
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800195 files[i] = (char*) malloc(dirLen + strlen(de->d_name) + 2);
196 strcpy(files[i], directory);
197 strcat(files[i], de->d_name);
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800198 if (fileExtensionOrDirectory == NULL)
199 strcat(files[i], "/");
200 i++;
201 }
202 if (pass == 1)
203 break;
204 if (total == 0)
205 break;
206 rewinddir(dir);
207 *numFiles = total;
208 files = (char**) malloc((total+1)*sizeof(char*));
209 files[total]=NULL;
210 }
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800211
212 if(closedir(dir) < 0) {
213 LOGE("Failed to close directory.");
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800214 }
215
216 if (total==0) {
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800217 return NULL;
218 }
219
Koushik Dutta1e8aaba2010-07-01 00:23:25 -0700220 // sort the result
221 if (files != NULL) {
222 for (i = 0; i < total; i++) {
223 int curMax = -1;
224 int j;
225 for (j = 0; j < total - i; j++) {
226 if (curMax == -1 || strcmp(files[curMax], files[j]) < 0)
227 curMax = j;
228 }
229 char* temp = files[curMax];
230 files[curMax] = files[total - i - 1];
231 files[total - i - 1] = temp;
232 }
233 }
234
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800235 return files;
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800236}
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800237
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800238// pass in NULL for fileExtensionOrDirectory and you will get a directory chooser
239char* choose_file_menu(const char* directory, const char* fileExtensionOrDirectory, const char* headers[])
240{
241 char path[PATH_MAX] = "";
242 DIR *dir;
243 struct dirent *de;
244 int numFiles = 0;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800245 int numDirs = 0;
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800246 int i;
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700247 char* return_value = NULL;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800248 int dir_len = strlen(directory);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800249
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800250 char** files = gather_files(directory, fileExtensionOrDirectory, &numFiles);
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800251 char** dirs = NULL;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800252 if (fileExtensionOrDirectory != NULL)
253 dirs = gather_files(directory, NULL, &numDirs);
254 int total = numDirs + numFiles;
255 if (total == 0)
256 {
257 ui_print("No files found.\n");
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800258 }
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700259 else
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800260 {
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700261 char** list = (char**) malloc((total + 1) * sizeof(char*));
262 list[total] = NULL;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800263
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800264
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700265 for (i = 0 ; i < numDirs; i++)
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800266 {
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700267 list[i] = strdup(dirs[i] + dir_len);
268 }
269
270 for (i = 0 ; i < numFiles; i++)
271 {
272 list[numDirs + i] = strdup(files[i] + dir_len);
273 }
274
275 for (;;)
276 {
277 int chosen_item = get_menu_selection(headers, list, 0);
278 if (chosen_item == GO_BACK)
279 break;
280 static char ret[PATH_MAX];
281 if (chosen_item < numDirs)
282 {
283 char* subret = choose_file_menu(dirs[chosen_item], fileExtensionOrDirectory, headers);
284 if (subret != NULL)
285 {
286 strcpy(ret, subret);
287 return_value = ret;
288 break;
289 }
290 continue;
291 }
292 strcpy(ret, files[chosen_item - numDirs]);
293 return_value = ret;
294 break;
295 }
296 free_string_array(list);
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800297 }
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700298
299 free_string_array(files);
300 free_string_array(dirs);
301 return return_value;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800302}
303
304void show_choose_zip_menu()
305{
Koushik K. Duttae9234872010-02-12 00:43:24 -0800306 if (ensure_root_path_mounted("SDCARD:") != 0) {
307 LOGE ("Can't mount /sdcard\n");
308 return;
309 }
310
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800311 static char* headers[] = { "Choose a zip to apply",
312 "",
313 NULL
314 };
315
316 char* file = choose_file_menu("/sdcard/", ".zip", headers);
317 if (file == NULL)
318 return;
319 char sdcard_package_file[1024];
320 strcpy(sdcard_package_file, "SDCARD:");
321 strcat(sdcard_package_file, file + strlen("/sdcard/"));
Koushik Duttad63eaef2010-07-14 21:01:21 -0700322 static char* confirm_install = "Confirm install?";
323 static char confirm[PATH_MAX];
324 sprintf(confirm, "Yes - Install %s", basename(file));
325 if (confirm_selection(confirm_install, confirm))
326 install_zip(sdcard_package_file);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800327}
328
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800329// This was pulled from bionic: The default system command always looks
330// for shell in /system/bin/sh. This is bad.
331#define _PATH_BSHELL "/sbin/sh"
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800332
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800333extern char **environ;
334int
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800335__system(const char *command)
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800336{
337 pid_t pid;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800338 sig_t intsave, quitsave;
339 sigset_t mask, omask;
340 int pstat;
341 char *argp[] = {"sh", "-c", NULL, NULL};
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800342
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800343 if (!command) /* just checking... */
344 return(1);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800345
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800346 argp[2] = (char *)command;
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800347
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800348 sigemptyset(&mask);
349 sigaddset(&mask, SIGCHLD);
350 sigprocmask(SIG_BLOCK, &mask, &omask);
351 switch (pid = vfork()) {
352 case -1: /* error */
353 sigprocmask(SIG_SETMASK, &omask, NULL);
354 return(-1);
355 case 0: /* child */
356 sigprocmask(SIG_SETMASK, &omask, NULL);
357 execve(_PATH_BSHELL, argp, environ);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800358 _exit(127);
359 }
360
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800361 intsave = (sig_t) bsd_signal(SIGINT, SIG_IGN);
362 quitsave = (sig_t) bsd_signal(SIGQUIT, SIG_IGN);
363 pid = waitpid(pid, (int *)&pstat, 0);
364 sigprocmask(SIG_SETMASK, &omask, NULL);
365 (void)bsd_signal(SIGINT, intsave);
366 (void)bsd_signal(SIGQUIT, quitsave);
367 return (pid == -1 ? -1 : pstat);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800368}
369
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800370void show_nandroid_restore_menu()
371{
Koushik K. Dutta54305a82010-03-12 17:43:26 -0800372 if (ensure_root_path_mounted("SDCARD:") != 0) {
373 LOGE ("Can't mount /sdcard\n");
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800374 return;
Koushik K. Dutta54305a82010-03-12 17:43:26 -0800375 }
376
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800377 static char* headers[] = { "Choose an image to restore",
378 "",
379 NULL
380 };
Koushik K. Duttae9234872010-02-12 00:43:24 -0800381
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800382 char* file = choose_file_menu("/sdcard/clockworkmod/backup/", NULL, headers);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800383 if (file == NULL)
384 return;
Koushik Duttad63eaef2010-07-14 21:01:21 -0700385
386 if (confirm_selection("Confirm restore?", "Yes - Restore"))
387 nandroid_restore(file, 1, 1, 1, 1, 1);
Koushik K. Dutta03173782010-02-26 14:14:23 -0800388}
389
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700390void show_mount_usb_storage_menu()
Koushik K. Dutta03173782010-02-26 14:14:23 -0800391{
Koushik Dutta598cfc72010-06-20 09:42:47 -0700392 char command[PATH_MAX];
393 sprintf(command, "echo %s > /sys/devices/platform/usb_mass_storage/lun0/file", SDCARD_DEVICE_PRIMARY);
394 __system(command);
Koushik K. Dutta03173782010-02-26 14:14:23 -0800395 static char* headers[] = { "USB Mass Storage device",
396 "Leaving this menu unmount",
397 "your SD card from your PC.",
398 "",
399 NULL
400 };
401
402 static char* list[] = { "Unmount", NULL };
403
404 for (;;)
405 {
406 int chosen_item = get_menu_selection(headers, list, 0);
407 if (chosen_item == GO_BACK || chosen_item == 0)
408 break;
409 }
410
Koushik K. Duttaf7215942010-03-16 13:34:51 -0700411 __system("echo '' > /sys/devices/platform/usb_mass_storage/lun0/file");
412 __system("echo 0 > /sys/devices/platform/usb_mass_storage/lun0/enable");
Koushik K. Duttae81cb752010-02-26 17:44:33 -0800413}
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800414
Koushik Duttad63eaef2010-07-14 21:01:21 -0700415int confirm_selection(const char* title, const char* confirm)
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700416{
Koushik Duttad63eaef2010-07-14 21:01:21 -0700417 char* confirm_headers[] = { title, " THIS CAN NOT BE UNDONE.", "", NULL };
418 char* items[] = { "No",
419 "No",
420 "No",
421 "No",
422 "No",
423 "No",
424 "No",
Koushik Duttaecd32fa2010-07-14 18:38:02 -0700425 confirm, //" Yes -- wipe partition", // [7
Koushik Duttad63eaef2010-07-14 21:01:21 -0700426 "No",
427 "No",
428 "No",
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700429 NULL };
430
Koushik Duttad63eaef2010-07-14 21:01:21 -0700431 int chosen_item = get_menu_selection(confirm_headers, items, 0);
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700432 return chosen_item == 7;
433}
434
Koushik Dutta2f73e582010-04-18 16:00:21 -0700435int format_non_mtd_device(const char* root)
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700436{
Koushik K. Duttaf3534d02010-04-18 18:06:24 -0700437 // if this is SDEXT:, don't worry about it.
438 if (0 == strcmp(root, "SDEXT:"))
439 {
440 struct stat st;
Koushik Dutta598cfc72010-06-20 09:42:47 -0700441 if (0 != stat(SDEXT_DEVICE, &st))
Koushik K. Duttaf3534d02010-04-18 18:06:24 -0700442 {
443 ui_print("No app2sd partition found. Skipping format of /sd-ext.\n");
444 return 0;
445 }
446 }
Koushik Dutta2f73e582010-04-18 16:00:21 -0700447
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700448 char path[PATH_MAX];
449 translate_root_path(root, path, PATH_MAX);
450 if (0 != ensure_root_path_mounted(root))
451 {
452 ui_print("Error mounting %s!\n", path);
Koushik Duttacd44ab92010-06-23 00:02:14 -0700453 ui_print("Skipping format...\n");
454 return 0;
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700455 }
456
457 static char tmp[PATH_MAX];
458 sprintf(tmp, "rm -rf %s/*", path);
459 __system(tmp);
460 sprintf(tmp, "rm -rf %s/.*", path);
461 __system(tmp);
462
463 ensure_root_path_unmounted(root);
464 return 0;
465}
466
467#define MOUNTABLE_COUNT 5
468#define MTD_COUNT 4
469#define MMC_COUNT 2
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700470
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700471void show_partition_menu()
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700472{
473 static char* headers[] = { "Mount and unmount partitions",
474 "",
475 NULL
476 };
477
478 typedef char* string;
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700479 string mounts[MOUNTABLE_COUNT][3] = {
480 { "mount /system", "unmount /system", "SYSTEM:" },
481 { "mount /data", "unmount /data", "DATA:" },
482 { "mount /cache", "unmount /cache", "CACHE:" },
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700483 { "mount /sdcard", "unmount /sdcard", "SDCARD:" },
484 { "mount /sd-ext", "unmount /sd-ext", "SDEXT:" }
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700485 };
486
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700487 string mtds[MTD_COUNT][2] = {
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700488 { "format boot", "BOOT:" },
489 { "format system", "SYSTEM:" },
490 { "format data", "DATA:" },
491 { "format cache", "CACHE:" },
492 };
493
494 string mmcs[MMC_COUNT][3] = {
495 { "format sdcard", "SDCARD:" },
Koushik K. Duttaa5f64e62010-04-05 15:44:57 -0700496 { "format sd-ext", "SDEXT:" }
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700497 };
Koushik Duttaecd32fa2010-07-14 18:38:02 -0700498
Koushik Duttad63eaef2010-07-14 21:01:21 -0700499 static char* confirm_format = "Confirm format?";
Koushik Duttaecd32fa2010-07-14 18:38:02 -0700500 static char* confirm = "Yes - Format";
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700501
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700502 for (;;)
503 {
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700504 int ismounted[MOUNTABLE_COUNT];
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700505 int i;
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700506 static string options[MOUNTABLE_COUNT + MTD_COUNT + MMC_COUNT + 1 + 1]; // mountables, format mtds, format mmcs, usb storage, null
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700507 for (i = 0; i < MOUNTABLE_COUNT; i++)
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700508 {
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700509 ismounted[i] = is_root_path_mounted(mounts[i][2]);
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700510 options[i] = ismounted[i] ? mounts[i][1] : mounts[i][0];
511 }
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700512
513 for (i = 0; i < MTD_COUNT; i++)
514 {
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700515 options[MOUNTABLE_COUNT + i] = mtds[i][0];
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700516 }
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700517
518 for (i = 0; i < MMC_COUNT; i++)
519 {
520 options[MOUNTABLE_COUNT + MTD_COUNT + i] = mmcs[i][0];
521 }
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700522
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700523 options[MOUNTABLE_COUNT + MTD_COUNT + MMC_COUNT] = "mount USB storage";
524 options[MOUNTABLE_COUNT + MTD_COUNT + MMC_COUNT + 1] = NULL;
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700525
526 int chosen_item = get_menu_selection(headers, options, 0);
527 if (chosen_item == GO_BACK)
528 break;
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700529 if (chosen_item == MOUNTABLE_COUNT + MTD_COUNT + MMC_COUNT)
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700530 {
531 show_mount_usb_storage_menu();
532 }
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700533 else if (chosen_item < MOUNTABLE_COUNT)
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700534 {
535 if (ismounted[chosen_item])
536 {
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700537 if (0 != ensure_root_path_unmounted(mounts[chosen_item][2]))
538 ui_print("Error unmounting %s!\n", mounts[chosen_item][2]);
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700539 }
540 else
541 {
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700542 if (0 != ensure_root_path_mounted(mounts[chosen_item][2]))
543 ui_print("Error mounting %s!\n", mounts[chosen_item][2]);
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700544 }
545 }
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700546 else if (chosen_item < MOUNTABLE_COUNT + MTD_COUNT)
547 {
548 chosen_item = chosen_item - MOUNTABLE_COUNT;
Koushik Duttaecd32fa2010-07-14 18:38:02 -0700549 if (!confirm_selection(confirm_format, confirm))
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700550 continue;
551 ui_print("Formatting %s...\n", mtds[chosen_item][1]);
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700552 if (0 != format_root_device(mtds[chosen_item][1]))
553 ui_print("Error formatting %s!\n", mtds[chosen_item][1]);
554 else
555 ui_print("Done.\n");
556 }
557 else if (chosen_item < MOUNTABLE_COUNT + MTD_COUNT + MMC_COUNT)
558 {
559 chosen_item = chosen_item - MOUNTABLE_COUNT - MTD_COUNT;
Koushik Duttaecd32fa2010-07-14 18:38:02 -0700560 if (!confirm_selection(confirm_format, confirm))
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700561 continue;
562 ui_print("Formatting %s...\n", mmcs[chosen_item][1]);
Koushik Dutta2f73e582010-04-18 16:00:21 -0700563 if (0 != format_non_mtd_device(mmcs[chosen_item][1]))
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700564 ui_print("Error formatting %s!\n", mmcs[chosen_item][1]);
565 else
566 ui_print("Done.\n");
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700567 }
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700568 }
569}
570
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800571#define EXTENDEDCOMMAND_SCRIPT "/cache/recovery/extendedcommand"
572
573int extendedcommand_file_exists()
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800574{
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800575 struct stat file_info;
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800576 return 0 == stat(EXTENDEDCOMMAND_SCRIPT, &file_info);
577}
578
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800579int run_script_from_buffer(char* script_data, int script_len, char* filename)
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800580{
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800581 /* Parse the script. Note that the script and parse tree are never freed.
582 */
583 const AmCommandList *commands = parseAmendScript(script_data, script_len);
584 if (commands == NULL) {
585 printf("Syntax error in update script\n");
586 return 1;
587 } else {
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800588 printf("Parsed %.*s\n", script_len, filename);
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800589 }
590
591 /* Execute the script.
592 */
593 int ret = execCommandList((ExecContext *)1, commands);
594 if (ret != 0) {
595 int num = ret;
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800596 char *line = NULL, *next = script_data;
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800597 while (next != NULL && ret-- > 0) {
598 line = next;
599 next = memchr(line, '\n', script_data + script_len - line);
600 if (next != NULL) *next++ = '\0';
601 }
602 printf("Failure at line %d:\n%s\n", num, next ? line : "(not found)");
603 return 1;
604 }
605
606 return 0;
607}
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800608
Koushik K. Dutta6771aca2010-04-03 23:28:39 -0700609int run_script(char* filename)
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800610{
611 struct stat file_info;
612 if (0 != stat(filename, &file_info)) {
613 printf("Error executing stat on file: %s\n", filename);
614 return 1;
615 }
616
617 int script_len = file_info.st_size;
Koushik K. Dutta707fa6d2010-03-23 11:44:33 -0700618 char* script_data = (char*)malloc(script_len + 1);
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800619 FILE *file = fopen(filename, "rb");
620 fread(script_data, script_len, 1, file);
Koushik K. Dutta707fa6d2010-03-23 11:44:33 -0700621 // supposedly not necessary, but let's be safe.
622 script_data[script_len] = '\0';
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800623 fclose(file);
Koushik Duttae25908b2010-06-21 08:16:19 -0700624 LOGI("Running script:\n");
625 LOGI("\n%s\n", script_data);
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800626
Koushik K. Duttaf3534d02010-04-18 18:06:24 -0700627 int ret = run_script_from_buffer(script_data, script_len, filename);
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700628 free(script_data);
629 return ret;
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800630}
631
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800632int run_and_remove_extendedcommand()
633{
Koushik K. Dutta6771aca2010-04-03 23:28:39 -0700634 char tmp[PATH_MAX];
635 sprintf(tmp, "cp %s /tmp/%s", EXTENDEDCOMMAND_SCRIPT, basename(EXTENDEDCOMMAND_SCRIPT));
636 __system(tmp);
637 remove(EXTENDEDCOMMAND_SCRIPT);
Koushik K. Dutta3a25cf52010-03-08 19:22:41 -0800638 int i = 0;
639 for (i = 20; i > 0; i--) {
640 ui_print("Waiting for SD Card to mount (%ds)\n", i);
641 if (ensure_root_path_mounted("SDCARD:") == 0) {
642 ui_print("SD Card mounted...\n");
643 break;
644 }
645 sleep(1);
646 }
Koushik Dutta92077c12010-07-15 00:10:08 -0700647 remove("/sdcard/clockworkmod/.recoverycheckpoint");
Koushik K. Dutta3a25cf52010-03-08 19:22:41 -0800648 if (i == 0) {
649 ui_print("Timed out waiting for SD card... continuing anyways.");
650 }
651
Koushik K. Dutta6771aca2010-04-03 23:28:39 -0700652 sprintf(tmp, "/tmp/%s", basename(EXTENDEDCOMMAND_SCRIPT));
653 return run_script(tmp);
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800654}
655
656int amend_main(int argc, char** argv)
657{
658 if (argc != 2)
659 {
660 printf("Usage: amend <script>\n");
661 return 0;
662 }
663
664 RecoveryCommandContext ctx = { NULL };
665 if (register_update_commands(&ctx)) {
666 LOGE("Can't install update commands\n");
667 }
Koushik K. Dutta6771aca2010-04-03 23:28:39 -0700668 return run_script(argv[1]);
Koushik K. Dutta5306db52010-03-08 14:09:35 -0800669}
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700670
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700671void show_nandroid_advanced_restore_menu()
672{
673 if (ensure_root_path_mounted("SDCARD:") != 0) {
674 LOGE ("Can't mount /sdcard\n");
675 return;
676 }
677
678 static char* advancedheaders[] = { "Choose an image to restore",
679 "",
680 "Choose an image to restore",
681 "first. The next menu will",
682 "you more options.",
683 "",
684 NULL
685 };
686
687 char* file = choose_file_menu("/sdcard/clockworkmod/backup/", NULL, advancedheaders);
688 if (file == NULL)
689 return;
690
691 static char* headers[] = { "Nandroid Advanced Restore",
692 "",
693 NULL
694 };
695
696 static char* list[] = { "Restore boot",
697 "Restore system",
698 "Restore data",
699 "Restore cache",
Koushik K. Dutta68b01902010-04-01 12:20:39 -0700700 "Restore sd-ext",
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700701 NULL
702 };
703
Koushik Duttad63eaef2010-07-14 21:01:21 -0700704
705 static char* confirm_restore = "Confirm restore?";
706
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700707 int chosen_item = get_menu_selection(headers, list, 0);
708 switch (chosen_item)
709 {
710 case 0:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700711 if (confirm_selection(confirm_restore, "Yes - Restore boot"))
712 nandroid_restore(file, 1, 0, 0, 0, 0);
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700713 break;
714 case 1:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700715 if (confirm_selection(confirm_restore, "Yes - Restore system"))
716 nandroid_restore(file, 0, 1, 0, 0, 0);
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700717 break;
718 case 2:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700719 if (confirm_selection(confirm_restore, "Yes - Restore data"))
720 nandroid_restore(file, 0, 0, 1, 0, 0);
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700721 break;
722 case 3:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700723 if (confirm_selection(confirm_restore, "Yes - Restore cache"))
724 nandroid_restore(file, 0, 0, 0, 1, 0);
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700725 break;
Koushik Dutta2f73e582010-04-18 16:00:21 -0700726 case 4:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700727 if (confirm_selection(confirm_restore, "Yes - Restore sd-ext"))
728 nandroid_restore(file, 0, 0, 0, 0, 1);
Koushik Dutta2f73e582010-04-18 16:00:21 -0700729 break;
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700730 }
731}
732
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700733void show_nandroid_menu()
734{
735 static char* headers[] = { "Nandroid",
736 "",
737 NULL
738 };
739
740 static char* list[] = { "Backup",
741 "Restore",
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700742 "Advanced Restore",
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700743 NULL
744 };
745
746 int chosen_item = get_menu_selection(headers, list, 0);
747 switch (chosen_item)
748 {
749 case 0:
750 {
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700751 char backup_path[PATH_MAX];
Koushik K. Dutta6a26e7c2010-03-27 15:26:11 -0700752 time_t t = time(NULL);
753 struct tm *tmp = localtime(&t);
754 if (tmp == NULL)
755 {
756 struct timeval tp;
757 gettimeofday(&tp, NULL);
758 sprintf(backup_path, "/sdcard/clockworkmod/backup/%d", tp.tv_sec);
759 }
760 else
761 {
762 strftime(backup_path, sizeof(backup_path), "/sdcard/clockworkmod/backup/%F.%H.%M.%S", tmp);
763 }
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700764 nandroid_backup(backup_path);
765 }
766 break;
767 case 1:
768 show_nandroid_restore_menu();
769 break;
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700770 case 2:
771 show_nandroid_advanced_restore_menu();
772 break;
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700773 }
Koushik K. Duttaa496b512010-03-19 14:51:45 -0700774}
775
Koushik Duttafd1579b2010-05-01 12:46:55 -0700776void wipe_battery_stats()
777{
778 ensure_root_path_mounted("DATA:");
779 remove("/data/system/batterystats.bin");
780 ensure_root_path_unmounted("DATA:");
781}
782
Koushik K. Duttaa496b512010-03-19 14:51:45 -0700783void show_advanced_menu()
784{
785 static char* headers[] = { "Advanced and Debugging Menu",
786 "",
787 NULL
788 };
789
Koushik K. Dutta7fe4d7b2010-04-06 23:04:52 -0700790 static char* list[] = { "Reboot Recovery",
Koushik Dutta49af23c2010-06-21 13:45:51 -0700791 "Wipe Dalvik Cache",
Koushik Duttafd1579b2010-05-01 12:46:55 -0700792 "Wipe Battery Stats",
Koushik Dutta598cfc72010-06-20 09:42:47 -0700793 "Report Error",
Koushik K. Dutta7fe4d7b2010-04-06 23:04:52 -0700794 "Key Test",
Koushik K. Duttaa496b512010-03-19 14:51:45 -0700795 NULL
796 };
797
798 for (;;)
799 {
800 int chosen_item = get_menu_selection(headers, list, 0);
801 if (chosen_item == GO_BACK)
802 break;
803 switch (chosen_item)
804 {
805 case 0:
Koushik K. Dutta7fe4d7b2010-04-06 23:04:52 -0700806 __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, "recovery");
807 break;
808 case 1:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700809 {
Koushik Dutta49af23c2010-06-21 13:45:51 -0700810 if (0 != ensure_root_path_mounted("DATA:"))
811 break;
Koushik Duttad63eaef2010-07-14 21:01:21 -0700812 if (confirm_selection( "Confirm wipe?", "Yes - Wipe Dalvik Cache"))
813 __system("rm -r /data/dalvik-cache");
Koushik Dutta49af23c2010-06-21 13:45:51 -0700814 ensure_root_path_unmounted("DATA:");
Koushik Duttafd1579b2010-05-01 12:46:55 -0700815 break;
Koushik Duttad63eaef2010-07-14 21:01:21 -0700816 }
Koushik Duttafd1579b2010-05-01 12:46:55 -0700817 case 2:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700818 {
819 if (confirm_selection( "Confirm wipe?", "Yes - Wipe Battery Stats"))
820 wipe_battery_stats();
Koushik Dutta598cfc72010-06-20 09:42:47 -0700821 break;
Koushik Duttad63eaef2010-07-14 21:01:21 -0700822 }
Koushik Dutta598cfc72010-06-20 09:42:47 -0700823 case 3:
Koushik Dutta49af23c2010-06-21 13:45:51 -0700824 handle_failure(1);
825 break;
826 case 4:
Koushik K. Duttaa496b512010-03-19 14:51:45 -0700827 {
828 ui_print("Outputting key codes.\n");
829 ui_print("Go back to end debugging.\n");
830 int key;
831 int action;
832 do
833 {
834 key = ui_wait_key();
835 action = device_handle_key(key, 1);
836 ui_print("Key: %d\n", key);
837 }
838 while (action != GO_BACK);
839 }
840 }
841 }
Koushik Dutta14239d22010-06-14 15:02:48 -0700842}
843
844void write_fstab_root(char *root_path, FILE *file)
845{
846 RootInfo *info = get_root_info_for_path(root_path);
Koushik Duttaa6522b32010-06-20 13:16:06 -0700847 if (info == NULL) {
848 LOGW("Unable to get root info for %s during fstab generation!", root_path);
Koushik Dutta598cfc72010-06-20 09:42:47 -0700849 return;
Koushik Duttaa6522b32010-06-20 13:16:06 -0700850 }
Koushik Dutta14239d22010-06-14 15:02:48 -0700851 MtdPartition *mtd = get_root_mtd_partition(root_path);
852 if (mtd != NULL)
853 {
854 fprintf(file, "/dev/block/mtdblock%d ", mtd->device_index);
855 }
856 else
857 {
Koushik Dutta8ec94182010-06-21 12:27:43 -0700858 // only SDCARD: seems to be using device2.
859 // and mmcblkXp1 is the fallback/device2.
860 // However, generally, mmcblkXp1 is usually where the
861 // FAT partition is located... so favor that.
862 if (NULL == info->device2)
863 fprintf(file, "%s ", info->device);
864 else
865 fprintf(file, "%s ", info->device2);
Koushik Dutta14239d22010-06-14 15:02:48 -0700866 }
867
868 fprintf(file, "%s ", info->mount_point);
869 fprintf(file, "%s rw\n", info->filesystem);
870}
871
872void create_fstab()
873{
Koushik Duttacd44ab92010-06-23 00:02:14 -0700874 __system("touch /etc/mtab");
Koushik Dutta14239d22010-06-14 15:02:48 -0700875 FILE *file = fopen("/etc/fstab", "w");
Koushik Duttaa6522b32010-06-20 13:16:06 -0700876 if (file == NULL) {
877 LOGW("Unable to create /etc/fstab!");
Koushik Dutta598cfc72010-06-20 09:42:47 -0700878 return;
Koushik Duttaa6522b32010-06-20 13:16:06 -0700879 }
Koushik Dutta14239d22010-06-14 15:02:48 -0700880 write_fstab_root("CACHE:", file);
881 write_fstab_root("DATA:", file);
Koushik Duttaa6522b32010-06-20 13:16:06 -0700882#ifdef HAS_DATADATA
883 write_fstab_root("DATADATA:", file);
884#endif
Koushik Dutta14239d22010-06-14 15:02:48 -0700885 write_fstab_root("SYSTEM:", file);
886 write_fstab_root("SDCARD:", file);
887 write_fstab_root("SDEXT:", file);
888 fclose(file);
Koushik Dutta598cfc72010-06-20 09:42:47 -0700889}
890
891void handle_failure(int ret)
892{
893 if (ret == 0)
894 return;
895 if (0 != ensure_root_path_mounted("SDCARD:"))
896 return;
Koushik Duttaa6522b32010-06-20 13:16:06 -0700897 mkdir("/sdcard/clockworkmod", S_IRWXU);
898 __system("cp /tmp/recovery.log /sdcard/clockworkmod/recovery.log");
Koushik Dutta598cfc72010-06-20 09:42:47 -0700899 ui_print("/tmp/recovery.log was copied to /sdcard/clockworkmod/recovery.log. Please open ROM Manager to report the issue.");
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700900}