blob: 507810bc9c38992340ab0fc8101d966bfb07ab1e [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);
Koushik Dutta5aaa8232010-07-20 16:23:18 -070064#ifndef BOARD_HAS_NO_MISC_PARTITION
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080065 set_sdcard_update_bootloader_message();
Koushik Dutta5aaa8232010-07-20 16:23:18 -070066#endif
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080067 int status = install_package(packagefilepath);
Koushik K. Duttaf3534d02010-04-18 18:06:24 -070068 ui_reset_progress();
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080069 if (status != INSTALL_SUCCESS) {
70 ui_set_background(BACKGROUND_ICON_ERROR);
71 ui_print("Installation aborted.\n");
Koushik K. Duttaea46fe22010-03-08 02:58:04 -080072 return 1;
Koushik K. Dutta79ce82c2010-02-25 12:03:17 -080073 }
Koushik Dutta5aaa8232010-07-20 16:23:18 -070074#ifndef BOARD_HAS_NO_MISC_PARTITION
Koushik K. Dutta79ce82c2010-02-25 12:03:17 -080075 if (firmware_update_pending()) {
76 ui_print("\nReboot via menu to complete\ninstallation.\n");
Koushik K. Dutta001c5b52010-02-25 14:53:57 -080077 }
Koushik Dutta5aaa8232010-07-20 16:23:18 -070078#endif
Koushik K. Dutta001c5b52010-02-25 14:53:57 -080079 ui_set_background(BACKGROUND_ICON_NONE);
Koushik K. Dutta99fb6fe2010-03-03 00:42:58 -080080 ui_print("\nInstall from sdcard complete.\n");
Koushik K. Duttaea46fe22010-03-08 02:58:04 -080081 return 0;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080082}
83
84char* INSTALL_MENU_ITEMS[] = { "apply sdcard:update.zip",
85 "choose zip from sdcard",
86 "toggle signature verification",
87 "toggle script asserts",
88 NULL };
89#define ITEM_APPLY_SDCARD 0
90#define ITEM_CHOOSE_ZIP 1
91#define ITEM_SIG_CHECK 2
92#define ITEM_ASSERTS 3
93
94void show_install_update_menu()
95{
96 static char* headers[] = { "Apply update from .zip file on SD card",
97 "",
98 NULL
99 };
100 for (;;)
101 {
102 int chosen_item = get_menu_selection(headers, INSTALL_MENU_ITEMS, 0);
103 switch (chosen_item)
104 {
105 case ITEM_ASSERTS:
106 toggle_script_asserts();
107 break;
108 case ITEM_SIG_CHECK:
109 toggle_signature_check();
110 break;
111 case ITEM_APPLY_SDCARD:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700112 {
113 if (confirm_selection("Confirm install?", "Yes - Install /sdcard/update.zip"))
114 install_zip(SDCARD_PACKAGE_FILE);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800115 break;
Koushik Duttad63eaef2010-07-14 21:01:21 -0700116 }
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800117 case ITEM_CHOOSE_ZIP:
118 show_choose_zip_menu();
119 break;
120 default:
121 return;
122 }
123
124 }
125}
126
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700127void free_string_array(char** array)
128{
129 if (array == NULL)
130 return;
131 char* cursor = array[0];
132 int i = 0;
133 while (cursor != NULL)
134 {
135 free(cursor);
136 cursor = array[++i];
137 }
138 free(array);
139}
140
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800141char** gather_files(const char* directory, const char* fileExtensionOrDirectory, int* numFiles)
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800142{
Koushik K. Duttae9234872010-02-12 00:43:24 -0800143 char path[PATH_MAX] = "";
144 DIR *dir;
145 struct dirent *de;
146 int total = 0;
147 int i;
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800148 char** files = NULL;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800149 int pass;
150 *numFiles = 0;
151 int dirLen = strlen(directory);
Koushik K. Duttae9234872010-02-12 00:43:24 -0800152
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800153 dir = opendir(directory);
154 if (dir == NULL) {
155 ui_print("Couldn't open directory.\n");
156 return NULL;
157 }
158
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800159 int extension_length = 0;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800160 if (fileExtensionOrDirectory != NULL)
161 extension_length = strlen(fileExtensionOrDirectory);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800162
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800163 int isCounting = 1;
164 i = 0;
165 for (pass = 0; pass < 2; pass++) {
166 while ((de=readdir(dir)) != NULL) {
167 // skip hidden files
168 if (de->d_name[0] == '.')
169 continue;
170
171 // NULL means that we are gathering directories, so skip this
172 if (fileExtensionOrDirectory != NULL)
173 {
174 // make sure that we can have the desired extension (prevent seg fault)
175 if (strlen(de->d_name) < extension_length)
176 continue;
177 // compare the extension
178 if (strcmp(de->d_name + strlen(de->d_name) - extension_length, fileExtensionOrDirectory) != 0)
179 continue;
180 }
181 else
182 {
183 struct stat info;
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700184 char fullFileName[PATH_MAX];
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800185 strcpy(fullFileName, directory);
186 strcat(fullFileName, de->d_name);
187 stat(fullFileName, &info);
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800188 // make sure it is a directory
189 if (!(S_ISDIR(info.st_mode)))
190 continue;
191 }
192
193 if (pass == 0)
194 {
195 total++;
196 continue;
197 }
198
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800199 files[i] = (char*) malloc(dirLen + strlen(de->d_name) + 2);
200 strcpy(files[i], directory);
201 strcat(files[i], de->d_name);
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800202 if (fileExtensionOrDirectory == NULL)
203 strcat(files[i], "/");
204 i++;
205 }
206 if (pass == 1)
207 break;
208 if (total == 0)
209 break;
210 rewinddir(dir);
211 *numFiles = total;
212 files = (char**) malloc((total+1)*sizeof(char*));
213 files[total]=NULL;
214 }
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800215
216 if(closedir(dir) < 0) {
217 LOGE("Failed to close directory.");
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800218 }
219
220 if (total==0) {
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800221 return NULL;
222 }
223
Koushik Dutta1e8aaba2010-07-01 00:23:25 -0700224 // sort the result
225 if (files != NULL) {
226 for (i = 0; i < total; i++) {
227 int curMax = -1;
228 int j;
229 for (j = 0; j < total - i; j++) {
230 if (curMax == -1 || strcmp(files[curMax], files[j]) < 0)
231 curMax = j;
232 }
233 char* temp = files[curMax];
234 files[curMax] = files[total - i - 1];
235 files[total - i - 1] = temp;
236 }
237 }
238
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800239 return files;
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800240}
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800241
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800242// pass in NULL for fileExtensionOrDirectory and you will get a directory chooser
243char* choose_file_menu(const char* directory, const char* fileExtensionOrDirectory, const char* headers[])
244{
245 char path[PATH_MAX] = "";
246 DIR *dir;
247 struct dirent *de;
248 int numFiles = 0;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800249 int numDirs = 0;
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800250 int i;
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700251 char* return_value = NULL;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800252 int dir_len = strlen(directory);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800253
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800254 char** files = gather_files(directory, fileExtensionOrDirectory, &numFiles);
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800255 char** dirs = NULL;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800256 if (fileExtensionOrDirectory != NULL)
257 dirs = gather_files(directory, NULL, &numDirs);
258 int total = numDirs + numFiles;
259 if (total == 0)
260 {
261 ui_print("No files found.\n");
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800262 }
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700263 else
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800264 {
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700265 char** list = (char**) malloc((total + 1) * sizeof(char*));
266 list[total] = NULL;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800267
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800268
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700269 for (i = 0 ; i < numDirs; i++)
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800270 {
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700271 list[i] = strdup(dirs[i] + dir_len);
272 }
273
274 for (i = 0 ; i < numFiles; i++)
275 {
276 list[numDirs + i] = strdup(files[i] + dir_len);
277 }
278
279 for (;;)
280 {
281 int chosen_item = get_menu_selection(headers, list, 0);
282 if (chosen_item == GO_BACK)
283 break;
284 static char ret[PATH_MAX];
285 if (chosen_item < numDirs)
286 {
287 char* subret = choose_file_menu(dirs[chosen_item], fileExtensionOrDirectory, headers);
288 if (subret != NULL)
289 {
290 strcpy(ret, subret);
291 return_value = ret;
292 break;
293 }
294 continue;
295 }
296 strcpy(ret, files[chosen_item - numDirs]);
297 return_value = ret;
298 break;
299 }
300 free_string_array(list);
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800301 }
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700302
303 free_string_array(files);
304 free_string_array(dirs);
305 return return_value;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800306}
307
308void show_choose_zip_menu()
309{
Koushik K. Duttae9234872010-02-12 00:43:24 -0800310 if (ensure_root_path_mounted("SDCARD:") != 0) {
311 LOGE ("Can't mount /sdcard\n");
312 return;
313 }
314
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800315 static char* headers[] = { "Choose a zip to apply",
316 "",
317 NULL
318 };
319
320 char* file = choose_file_menu("/sdcard/", ".zip", headers);
321 if (file == NULL)
322 return;
323 char sdcard_package_file[1024];
324 strcpy(sdcard_package_file, "SDCARD:");
325 strcat(sdcard_package_file, file + strlen("/sdcard/"));
Koushik Duttad63eaef2010-07-14 21:01:21 -0700326 static char* confirm_install = "Confirm install?";
327 static char confirm[PATH_MAX];
328 sprintf(confirm, "Yes - Install %s", basename(file));
329 if (confirm_selection(confirm_install, confirm))
330 install_zip(sdcard_package_file);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800331}
332
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800333// This was pulled from bionic: The default system command always looks
334// for shell in /system/bin/sh. This is bad.
335#define _PATH_BSHELL "/sbin/sh"
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800336
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800337extern char **environ;
338int
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800339__system(const char *command)
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800340{
341 pid_t pid;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800342 sig_t intsave, quitsave;
343 sigset_t mask, omask;
344 int pstat;
345 char *argp[] = {"sh", "-c", NULL, NULL};
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800346
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800347 if (!command) /* just checking... */
348 return(1);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800349
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800350 argp[2] = (char *)command;
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800351
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800352 sigemptyset(&mask);
353 sigaddset(&mask, SIGCHLD);
354 sigprocmask(SIG_BLOCK, &mask, &omask);
355 switch (pid = vfork()) {
356 case -1: /* error */
357 sigprocmask(SIG_SETMASK, &omask, NULL);
358 return(-1);
359 case 0: /* child */
360 sigprocmask(SIG_SETMASK, &omask, NULL);
361 execve(_PATH_BSHELL, argp, environ);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800362 _exit(127);
363 }
364
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800365 intsave = (sig_t) bsd_signal(SIGINT, SIG_IGN);
366 quitsave = (sig_t) bsd_signal(SIGQUIT, SIG_IGN);
367 pid = waitpid(pid, (int *)&pstat, 0);
368 sigprocmask(SIG_SETMASK, &omask, NULL);
369 (void)bsd_signal(SIGINT, intsave);
370 (void)bsd_signal(SIGQUIT, quitsave);
371 return (pid == -1 ? -1 : pstat);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800372}
373
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800374void show_nandroid_restore_menu()
375{
Koushik K. Dutta54305a82010-03-12 17:43:26 -0800376 if (ensure_root_path_mounted("SDCARD:") != 0) {
377 LOGE ("Can't mount /sdcard\n");
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800378 return;
Koushik K. Dutta54305a82010-03-12 17:43:26 -0800379 }
380
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800381 static char* headers[] = { "Choose an image to restore",
382 "",
383 NULL
384 };
Koushik K. Duttae9234872010-02-12 00:43:24 -0800385
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800386 char* file = choose_file_menu("/sdcard/clockworkmod/backup/", NULL, headers);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800387 if (file == NULL)
388 return;
Koushik Duttad63eaef2010-07-14 21:01:21 -0700389
390 if (confirm_selection("Confirm restore?", "Yes - Restore"))
391 nandroid_restore(file, 1, 1, 1, 1, 1);
Koushik K. Dutta03173782010-02-26 14:14:23 -0800392}
393
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700394void show_mount_usb_storage_menu()
Koushik K. Dutta03173782010-02-26 14:14:23 -0800395{
Koushik Dutta598cfc72010-06-20 09:42:47 -0700396 char command[PATH_MAX];
397 sprintf(command, "echo %s > /sys/devices/platform/usb_mass_storage/lun0/file", SDCARD_DEVICE_PRIMARY);
398 __system(command);
Koushik K. Dutta03173782010-02-26 14:14:23 -0800399 static char* headers[] = { "USB Mass Storage device",
400 "Leaving this menu unmount",
401 "your SD card from your PC.",
402 "",
403 NULL
404 };
405
406 static char* list[] = { "Unmount", NULL };
407
408 for (;;)
409 {
410 int chosen_item = get_menu_selection(headers, list, 0);
411 if (chosen_item == GO_BACK || chosen_item == 0)
412 break;
413 }
414
Koushik K. Duttaf7215942010-03-16 13:34:51 -0700415 __system("echo '' > /sys/devices/platform/usb_mass_storage/lun0/file");
416 __system("echo 0 > /sys/devices/platform/usb_mass_storage/lun0/enable");
Koushik K. Duttae81cb752010-02-26 17:44:33 -0800417}
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800418
Koushik Duttad63eaef2010-07-14 21:01:21 -0700419int confirm_selection(const char* title, const char* confirm)
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700420{
Koushik Duttad63eaef2010-07-14 21:01:21 -0700421 char* confirm_headers[] = { title, " THIS CAN NOT BE UNDONE.", "", NULL };
422 char* items[] = { "No",
423 "No",
424 "No",
425 "No",
426 "No",
427 "No",
428 "No",
Koushik Duttaecd32fa2010-07-14 18:38:02 -0700429 confirm, //" Yes -- wipe partition", // [7
Koushik Duttad63eaef2010-07-14 21:01:21 -0700430 "No",
431 "No",
432 "No",
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700433 NULL };
434
Koushik Duttad63eaef2010-07-14 21:01:21 -0700435 int chosen_item = get_menu_selection(confirm_headers, items, 0);
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700436 return chosen_item == 7;
437}
438
Koushik Dutta2f73e582010-04-18 16:00:21 -0700439int format_non_mtd_device(const char* root)
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700440{
Koushik K. Duttaf3534d02010-04-18 18:06:24 -0700441 // if this is SDEXT:, don't worry about it.
442 if (0 == strcmp(root, "SDEXT:"))
443 {
444 struct stat st;
Koushik Dutta598cfc72010-06-20 09:42:47 -0700445 if (0 != stat(SDEXT_DEVICE, &st))
Koushik K. Duttaf3534d02010-04-18 18:06:24 -0700446 {
447 ui_print("No app2sd partition found. Skipping format of /sd-ext.\n");
448 return 0;
449 }
450 }
Koushik Dutta2f73e582010-04-18 16:00:21 -0700451
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700452 char path[PATH_MAX];
453 translate_root_path(root, path, PATH_MAX);
454 if (0 != ensure_root_path_mounted(root))
455 {
456 ui_print("Error mounting %s!\n", path);
Koushik Duttacd44ab92010-06-23 00:02:14 -0700457 ui_print("Skipping format...\n");
458 return 0;
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700459 }
460
461 static char tmp[PATH_MAX];
462 sprintf(tmp, "rm -rf %s/*", path);
463 __system(tmp);
464 sprintf(tmp, "rm -rf %s/.*", path);
465 __system(tmp);
466
467 ensure_root_path_unmounted(root);
468 return 0;
469}
470
471#define MOUNTABLE_COUNT 5
472#define MTD_COUNT 4
473#define MMC_COUNT 2
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700474
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700475void show_partition_menu()
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700476{
477 static char* headers[] = { "Mount and unmount partitions",
478 "",
479 NULL
480 };
481
482 typedef char* string;
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700483 string mounts[MOUNTABLE_COUNT][3] = {
484 { "mount /system", "unmount /system", "SYSTEM:" },
485 { "mount /data", "unmount /data", "DATA:" },
486 { "mount /cache", "unmount /cache", "CACHE:" },
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700487 { "mount /sdcard", "unmount /sdcard", "SDCARD:" },
488 { "mount /sd-ext", "unmount /sd-ext", "SDEXT:" }
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700489 };
490
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700491 string mtds[MTD_COUNT][2] = {
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700492 { "format boot", "BOOT:" },
493 { "format system", "SYSTEM:" },
494 { "format data", "DATA:" },
495 { "format cache", "CACHE:" },
496 };
497
498 string mmcs[MMC_COUNT][3] = {
499 { "format sdcard", "SDCARD:" },
Koushik K. Duttaa5f64e62010-04-05 15:44:57 -0700500 { "format sd-ext", "SDEXT:" }
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700501 };
Koushik Duttaecd32fa2010-07-14 18:38:02 -0700502
Koushik Duttad63eaef2010-07-14 21:01:21 -0700503 static char* confirm_format = "Confirm format?";
Koushik Duttaecd32fa2010-07-14 18:38:02 -0700504 static char* confirm = "Yes - Format";
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700505
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700506 for (;;)
507 {
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700508 int ismounted[MOUNTABLE_COUNT];
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700509 int i;
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700510 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 -0700511 for (i = 0; i < MOUNTABLE_COUNT; i++)
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700512 {
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700513 ismounted[i] = is_root_path_mounted(mounts[i][2]);
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700514 options[i] = ismounted[i] ? mounts[i][1] : mounts[i][0];
515 }
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700516
517 for (i = 0; i < MTD_COUNT; i++)
518 {
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700519 options[MOUNTABLE_COUNT + i] = mtds[i][0];
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700520 }
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700521
522 for (i = 0; i < MMC_COUNT; i++)
523 {
524 options[MOUNTABLE_COUNT + MTD_COUNT + i] = mmcs[i][0];
525 }
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700526
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700527 options[MOUNTABLE_COUNT + MTD_COUNT + MMC_COUNT] = "mount USB storage";
528 options[MOUNTABLE_COUNT + MTD_COUNT + MMC_COUNT + 1] = NULL;
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700529
530 int chosen_item = get_menu_selection(headers, options, 0);
531 if (chosen_item == GO_BACK)
532 break;
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700533 if (chosen_item == MOUNTABLE_COUNT + MTD_COUNT + MMC_COUNT)
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700534 {
535 show_mount_usb_storage_menu();
536 }
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700537 else if (chosen_item < MOUNTABLE_COUNT)
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700538 {
539 if (ismounted[chosen_item])
540 {
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700541 if (0 != ensure_root_path_unmounted(mounts[chosen_item][2]))
542 ui_print("Error unmounting %s!\n", mounts[chosen_item][2]);
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700543 }
544 else
545 {
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700546 if (0 != ensure_root_path_mounted(mounts[chosen_item][2]))
547 ui_print("Error mounting %s!\n", mounts[chosen_item][2]);
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700548 }
549 }
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700550 else if (chosen_item < MOUNTABLE_COUNT + MTD_COUNT)
551 {
552 chosen_item = chosen_item - MOUNTABLE_COUNT;
Koushik Duttaecd32fa2010-07-14 18:38:02 -0700553 if (!confirm_selection(confirm_format, confirm))
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700554 continue;
555 ui_print("Formatting %s...\n", mtds[chosen_item][1]);
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700556 if (0 != format_root_device(mtds[chosen_item][1]))
557 ui_print("Error formatting %s!\n", mtds[chosen_item][1]);
558 else
559 ui_print("Done.\n");
560 }
561 else if (chosen_item < MOUNTABLE_COUNT + MTD_COUNT + MMC_COUNT)
562 {
563 chosen_item = chosen_item - MOUNTABLE_COUNT - MTD_COUNT;
Koushik Duttaecd32fa2010-07-14 18:38:02 -0700564 if (!confirm_selection(confirm_format, confirm))
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700565 continue;
566 ui_print("Formatting %s...\n", mmcs[chosen_item][1]);
Koushik Dutta2f73e582010-04-18 16:00:21 -0700567 if (0 != format_non_mtd_device(mmcs[chosen_item][1]))
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700568 ui_print("Error formatting %s!\n", mmcs[chosen_item][1]);
569 else
570 ui_print("Done.\n");
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700571 }
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700572 }
573}
574
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800575#define EXTENDEDCOMMAND_SCRIPT "/cache/recovery/extendedcommand"
576
577int extendedcommand_file_exists()
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800578{
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800579 struct stat file_info;
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800580 return 0 == stat(EXTENDEDCOMMAND_SCRIPT, &file_info);
581}
582
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800583int run_script_from_buffer(char* script_data, int script_len, char* filename)
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800584{
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800585 /* Parse the script. Note that the script and parse tree are never freed.
586 */
587 const AmCommandList *commands = parseAmendScript(script_data, script_len);
588 if (commands == NULL) {
589 printf("Syntax error in update script\n");
590 return 1;
591 } else {
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800592 printf("Parsed %.*s\n", script_len, filename);
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800593 }
594
595 /* Execute the script.
596 */
597 int ret = execCommandList((ExecContext *)1, commands);
598 if (ret != 0) {
599 int num = ret;
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800600 char *line = NULL, *next = script_data;
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800601 while (next != NULL && ret-- > 0) {
602 line = next;
603 next = memchr(line, '\n', script_data + script_len - line);
604 if (next != NULL) *next++ = '\0';
605 }
606 printf("Failure at line %d:\n%s\n", num, next ? line : "(not found)");
607 return 1;
608 }
609
610 return 0;
611}
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800612
Koushik K. Dutta6771aca2010-04-03 23:28:39 -0700613int run_script(char* filename)
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800614{
615 struct stat file_info;
616 if (0 != stat(filename, &file_info)) {
617 printf("Error executing stat on file: %s\n", filename);
618 return 1;
619 }
620
621 int script_len = file_info.st_size;
Koushik K. Dutta707fa6d2010-03-23 11:44:33 -0700622 char* script_data = (char*)malloc(script_len + 1);
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800623 FILE *file = fopen(filename, "rb");
624 fread(script_data, script_len, 1, file);
Koushik K. Dutta707fa6d2010-03-23 11:44:33 -0700625 // supposedly not necessary, but let's be safe.
626 script_data[script_len] = '\0';
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800627 fclose(file);
Koushik Duttae25908b2010-06-21 08:16:19 -0700628 LOGI("Running script:\n");
629 LOGI("\n%s\n", script_data);
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800630
Koushik K. Duttaf3534d02010-04-18 18:06:24 -0700631 int ret = run_script_from_buffer(script_data, script_len, filename);
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700632 free(script_data);
633 return ret;
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800634}
635
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800636int run_and_remove_extendedcommand()
637{
Koushik K. Dutta6771aca2010-04-03 23:28:39 -0700638 char tmp[PATH_MAX];
639 sprintf(tmp, "cp %s /tmp/%s", EXTENDEDCOMMAND_SCRIPT, basename(EXTENDEDCOMMAND_SCRIPT));
640 __system(tmp);
641 remove(EXTENDEDCOMMAND_SCRIPT);
Koushik K. Dutta3a25cf52010-03-08 19:22:41 -0800642 int i = 0;
643 for (i = 20; i > 0; i--) {
644 ui_print("Waiting for SD Card to mount (%ds)\n", i);
645 if (ensure_root_path_mounted("SDCARD:") == 0) {
646 ui_print("SD Card mounted...\n");
647 break;
648 }
649 sleep(1);
650 }
Koushik Dutta92077c12010-07-15 00:10:08 -0700651 remove("/sdcard/clockworkmod/.recoverycheckpoint");
Koushik K. Dutta3a25cf52010-03-08 19:22:41 -0800652 if (i == 0) {
653 ui_print("Timed out waiting for SD card... continuing anyways.");
654 }
655
Koushik K. Dutta6771aca2010-04-03 23:28:39 -0700656 sprintf(tmp, "/tmp/%s", basename(EXTENDEDCOMMAND_SCRIPT));
657 return run_script(tmp);
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800658}
659
660int amend_main(int argc, char** argv)
661{
662 if (argc != 2)
663 {
664 printf("Usage: amend <script>\n");
665 return 0;
666 }
667
668 RecoveryCommandContext ctx = { NULL };
669 if (register_update_commands(&ctx)) {
670 LOGE("Can't install update commands\n");
671 }
Koushik K. Dutta6771aca2010-04-03 23:28:39 -0700672 return run_script(argv[1]);
Koushik K. Dutta5306db52010-03-08 14:09:35 -0800673}
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700674
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700675void show_nandroid_advanced_restore_menu()
676{
677 if (ensure_root_path_mounted("SDCARD:") != 0) {
678 LOGE ("Can't mount /sdcard\n");
679 return;
680 }
681
682 static char* advancedheaders[] = { "Choose an image to restore",
683 "",
684 "Choose an image to restore",
685 "first. The next menu will",
686 "you more options.",
687 "",
688 NULL
689 };
690
691 char* file = choose_file_menu("/sdcard/clockworkmod/backup/", NULL, advancedheaders);
692 if (file == NULL)
693 return;
694
695 static char* headers[] = { "Nandroid Advanced Restore",
696 "",
697 NULL
698 };
699
700 static char* list[] = { "Restore boot",
701 "Restore system",
702 "Restore data",
703 "Restore cache",
Koushik K. Dutta68b01902010-04-01 12:20:39 -0700704 "Restore sd-ext",
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700705 NULL
706 };
707
Koushik Duttad63eaef2010-07-14 21:01:21 -0700708
709 static char* confirm_restore = "Confirm restore?";
710
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700711 int chosen_item = get_menu_selection(headers, list, 0);
712 switch (chosen_item)
713 {
714 case 0:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700715 if (confirm_selection(confirm_restore, "Yes - Restore boot"))
716 nandroid_restore(file, 1, 0, 0, 0, 0);
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700717 break;
718 case 1:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700719 if (confirm_selection(confirm_restore, "Yes - Restore system"))
720 nandroid_restore(file, 0, 1, 0, 0, 0);
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700721 break;
722 case 2:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700723 if (confirm_selection(confirm_restore, "Yes - Restore data"))
724 nandroid_restore(file, 0, 0, 1, 0, 0);
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700725 break;
726 case 3:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700727 if (confirm_selection(confirm_restore, "Yes - Restore cache"))
728 nandroid_restore(file, 0, 0, 0, 1, 0);
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700729 break;
Koushik Dutta2f73e582010-04-18 16:00:21 -0700730 case 4:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700731 if (confirm_selection(confirm_restore, "Yes - Restore sd-ext"))
732 nandroid_restore(file, 0, 0, 0, 0, 1);
Koushik Dutta2f73e582010-04-18 16:00:21 -0700733 break;
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700734 }
735}
736
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700737void show_nandroid_menu()
738{
739 static char* headers[] = { "Nandroid",
740 "",
741 NULL
742 };
743
744 static char* list[] = { "Backup",
745 "Restore",
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700746 "Advanced Restore",
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700747 NULL
748 };
749
750 int chosen_item = get_menu_selection(headers, list, 0);
751 switch (chosen_item)
752 {
753 case 0:
754 {
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700755 char backup_path[PATH_MAX];
Koushik K. Dutta6a26e7c2010-03-27 15:26:11 -0700756 time_t t = time(NULL);
757 struct tm *tmp = localtime(&t);
758 if (tmp == NULL)
759 {
760 struct timeval tp;
761 gettimeofday(&tp, NULL);
762 sprintf(backup_path, "/sdcard/clockworkmod/backup/%d", tp.tv_sec);
763 }
764 else
765 {
766 strftime(backup_path, sizeof(backup_path), "/sdcard/clockworkmod/backup/%F.%H.%M.%S", tmp);
767 }
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700768 nandroid_backup(backup_path);
769 }
770 break;
771 case 1:
772 show_nandroid_restore_menu();
773 break;
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700774 case 2:
775 show_nandroid_advanced_restore_menu();
776 break;
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700777 }
Koushik K. Duttaa496b512010-03-19 14:51:45 -0700778}
779
Koushik Duttafd1579b2010-05-01 12:46:55 -0700780void wipe_battery_stats()
781{
782 ensure_root_path_mounted("DATA:");
783 remove("/data/system/batterystats.bin");
784 ensure_root_path_unmounted("DATA:");
785}
786
Koushik K. Duttaa496b512010-03-19 14:51:45 -0700787void show_advanced_menu()
788{
789 static char* headers[] = { "Advanced and Debugging Menu",
790 "",
791 NULL
792 };
793
Koushik K. Dutta7fe4d7b2010-04-06 23:04:52 -0700794 static char* list[] = { "Reboot Recovery",
Koushik Dutta49af23c2010-06-21 13:45:51 -0700795 "Wipe Dalvik Cache",
Koushik Duttafd1579b2010-05-01 12:46:55 -0700796 "Wipe Battery Stats",
Koushik Dutta598cfc72010-06-20 09:42:47 -0700797 "Report Error",
Koushik K. Dutta7fe4d7b2010-04-06 23:04:52 -0700798 "Key Test",
Koushik K. Duttaa496b512010-03-19 14:51:45 -0700799 NULL
800 };
801
802 for (;;)
803 {
804 int chosen_item = get_menu_selection(headers, list, 0);
805 if (chosen_item == GO_BACK)
806 break;
807 switch (chosen_item)
808 {
809 case 0:
Koushik K. Dutta7fe4d7b2010-04-06 23:04:52 -0700810 __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, "recovery");
811 break;
812 case 1:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700813 {
Koushik Dutta49af23c2010-06-21 13:45:51 -0700814 if (0 != ensure_root_path_mounted("DATA:"))
815 break;
Koushik Dutta6c7745d2010-08-07 12:17:13 -0700816 ensure_root_path_mounted("SDEXT:");
817 ensure_root_path_mounted("CACHE:");
818 if (confirm_selection( "Confirm wipe?", "Yes - Wipe Dalvik Cache")) {
Koushik Duttad63eaef2010-07-14 21:01:21 -0700819 __system("rm -r /data/dalvik-cache");
Koushik Dutta6c7745d2010-08-07 12:17:13 -0700820 __system("rm -r /cache/dalvik-cache");
821 __system("rm -r /sd-ext/dalvik-cache");
822 }
Koushik Dutta49af23c2010-06-21 13:45:51 -0700823 ensure_root_path_unmounted("DATA:");
Koushik Dutta6c7745d2010-08-07 12:17:13 -0700824 ui_print("Dalvik Cache wiped.\n");
Koushik Duttafd1579b2010-05-01 12:46:55 -0700825 break;
Koushik Duttad63eaef2010-07-14 21:01:21 -0700826 }
Koushik Duttafd1579b2010-05-01 12:46:55 -0700827 case 2:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700828 {
829 if (confirm_selection( "Confirm wipe?", "Yes - Wipe Battery Stats"))
830 wipe_battery_stats();
Koushik Dutta598cfc72010-06-20 09:42:47 -0700831 break;
Koushik Duttad63eaef2010-07-14 21:01:21 -0700832 }
Koushik Dutta598cfc72010-06-20 09:42:47 -0700833 case 3:
Koushik Dutta49af23c2010-06-21 13:45:51 -0700834 handle_failure(1);
835 break;
836 case 4:
Koushik K. Duttaa496b512010-03-19 14:51:45 -0700837 {
838 ui_print("Outputting key codes.\n");
839 ui_print("Go back to end debugging.\n");
840 int key;
841 int action;
842 do
843 {
844 key = ui_wait_key();
845 action = device_handle_key(key, 1);
846 ui_print("Key: %d\n", key);
847 }
848 while (action != GO_BACK);
849 }
850 }
851 }
Koushik Dutta14239d22010-06-14 15:02:48 -0700852}
853
854void write_fstab_root(char *root_path, FILE *file)
855{
856 RootInfo *info = get_root_info_for_path(root_path);
Koushik Duttaa6522b32010-06-20 13:16:06 -0700857 if (info == NULL) {
858 LOGW("Unable to get root info for %s during fstab generation!", root_path);
Koushik Dutta598cfc72010-06-20 09:42:47 -0700859 return;
Koushik Duttaa6522b32010-06-20 13:16:06 -0700860 }
Koushik Dutta14239d22010-06-14 15:02:48 -0700861 MtdPartition *mtd = get_root_mtd_partition(root_path);
862 if (mtd != NULL)
863 {
864 fprintf(file, "/dev/block/mtdblock%d ", mtd->device_index);
865 }
866 else
867 {
Koushik Dutta8ec94182010-06-21 12:27:43 -0700868 // only SDCARD: seems to be using device2.
869 // and mmcblkXp1 is the fallback/device2.
870 // However, generally, mmcblkXp1 is usually where the
871 // FAT partition is located... so favor that.
872 if (NULL == info->device2)
873 fprintf(file, "%s ", info->device);
874 else
875 fprintf(file, "%s ", info->device2);
Koushik Dutta14239d22010-06-14 15:02:48 -0700876 }
877
878 fprintf(file, "%s ", info->mount_point);
Koushik Duttad4060c32010-07-22 20:14:44 -0700879 fprintf(file, "%s %s\n", info->filesystem, info->filesystem_options == NULL ? "rw" : info->filesystem_options);
Koushik Dutta14239d22010-06-14 15:02:48 -0700880}
881
882void create_fstab()
883{
Koushik Duttacd44ab92010-06-23 00:02:14 -0700884 __system("touch /etc/mtab");
Koushik Dutta14239d22010-06-14 15:02:48 -0700885 FILE *file = fopen("/etc/fstab", "w");
Koushik Duttaa6522b32010-06-20 13:16:06 -0700886 if (file == NULL) {
887 LOGW("Unable to create /etc/fstab!");
Koushik Dutta598cfc72010-06-20 09:42:47 -0700888 return;
Koushik Duttaa6522b32010-06-20 13:16:06 -0700889 }
Koushik Dutta14239d22010-06-14 15:02:48 -0700890 write_fstab_root("CACHE:", file);
891 write_fstab_root("DATA:", file);
Koushik Duttaa6522b32010-06-20 13:16:06 -0700892#ifdef HAS_DATADATA
893 write_fstab_root("DATADATA:", file);
894#endif
Koushik Dutta14239d22010-06-14 15:02:48 -0700895 write_fstab_root("SYSTEM:", file);
896 write_fstab_root("SDCARD:", file);
897 write_fstab_root("SDEXT:", file);
898 fclose(file);
Koushik Dutta598cfc72010-06-20 09:42:47 -0700899}
900
901void handle_failure(int ret)
902{
903 if (ret == 0)
904 return;
905 if (0 != ensure_root_path_mounted("SDCARD:"))
906 return;
Koushik Duttaa6522b32010-06-20 13:16:06 -0700907 mkdir("/sdcard/clockworkmod", S_IRWXU);
908 __system("cp /tmp/recovery.log /sdcard/clockworkmod/recovery.log");
Koushik Dutta598cfc72010-06-20 09:42:47 -0700909 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 -0700910}