blob: d70e0fdc52422fd643284c08c60da6e0ca799c05 [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 Duttaceddcd52010-08-23 16:13:14 -0700421 struct stat info;
422 if (0 == stat("/sdcard/clockworkmod/.no_confirm", &info))
423 return 1;
424
Koushik Duttad63eaef2010-07-14 21:01:21 -0700425 char* confirm_headers[] = { title, " THIS CAN NOT BE UNDONE.", "", NULL };
426 char* items[] = { "No",
427 "No",
428 "No",
429 "No",
430 "No",
431 "No",
432 "No",
Koushik Duttaecd32fa2010-07-14 18:38:02 -0700433 confirm, //" Yes -- wipe partition", // [7
Koushik Duttad63eaef2010-07-14 21:01:21 -0700434 "No",
435 "No",
436 "No",
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700437 NULL };
438
Koushik Duttad63eaef2010-07-14 21:01:21 -0700439 int chosen_item = get_menu_selection(confirm_headers, items, 0);
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700440 return chosen_item == 7;
441}
442
Koushik Dutta2f73e582010-04-18 16:00:21 -0700443int format_non_mtd_device(const char* root)
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700444{
Koushik K. Duttaf3534d02010-04-18 18:06:24 -0700445 // if this is SDEXT:, don't worry about it.
446 if (0 == strcmp(root, "SDEXT:"))
447 {
448 struct stat st;
Koushik Dutta598cfc72010-06-20 09:42:47 -0700449 if (0 != stat(SDEXT_DEVICE, &st))
Koushik K. Duttaf3534d02010-04-18 18:06:24 -0700450 {
451 ui_print("No app2sd partition found. Skipping format of /sd-ext.\n");
452 return 0;
453 }
454 }
Koushik Dutta2f73e582010-04-18 16:00:21 -0700455
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700456 char path[PATH_MAX];
457 translate_root_path(root, path, PATH_MAX);
458 if (0 != ensure_root_path_mounted(root))
459 {
460 ui_print("Error mounting %s!\n", path);
Koushik Duttacd44ab92010-06-23 00:02:14 -0700461 ui_print("Skipping format...\n");
462 return 0;
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700463 }
464
465 static char tmp[PATH_MAX];
466 sprintf(tmp, "rm -rf %s/*", path);
467 __system(tmp);
468 sprintf(tmp, "rm -rf %s/.*", path);
469 __system(tmp);
470
471 ensure_root_path_unmounted(root);
472 return 0;
473}
474
475#define MOUNTABLE_COUNT 5
476#define MTD_COUNT 4
477#define MMC_COUNT 2
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700478
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700479void show_partition_menu()
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700480{
Koushik Duttaceddcd52010-08-23 16:13:14 -0700481 static char* headers[] = { "Mounts and Storage Menu",
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700482 "",
483 NULL
484 };
485
486 typedef char* string;
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700487 string mounts[MOUNTABLE_COUNT][3] = {
488 { "mount /system", "unmount /system", "SYSTEM:" },
489 { "mount /data", "unmount /data", "DATA:" },
490 { "mount /cache", "unmount /cache", "CACHE:" },
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700491 { "mount /sdcard", "unmount /sdcard", "SDCARD:" },
492 { "mount /sd-ext", "unmount /sd-ext", "SDEXT:" }
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700493 };
494
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700495 string mtds[MTD_COUNT][2] = {
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700496 { "format boot", "BOOT:" },
497 { "format system", "SYSTEM:" },
498 { "format data", "DATA:" },
499 { "format cache", "CACHE:" },
500 };
501
502 string mmcs[MMC_COUNT][3] = {
503 { "format sdcard", "SDCARD:" },
Koushik K. Duttaa5f64e62010-04-05 15:44:57 -0700504 { "format sd-ext", "SDEXT:" }
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700505 };
Koushik Duttaecd32fa2010-07-14 18:38:02 -0700506
Koushik Duttad63eaef2010-07-14 21:01:21 -0700507 static char* confirm_format = "Confirm format?";
Koushik Duttaecd32fa2010-07-14 18:38:02 -0700508 static char* confirm = "Yes - Format";
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700509
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700510 for (;;)
511 {
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700512 int ismounted[MOUNTABLE_COUNT];
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700513 int i;
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700514 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 -0700515 for (i = 0; i < MOUNTABLE_COUNT; i++)
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700516 {
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700517 ismounted[i] = is_root_path_mounted(mounts[i][2]);
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700518 options[i] = ismounted[i] ? mounts[i][1] : mounts[i][0];
519 }
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700520
521 for (i = 0; i < MTD_COUNT; i++)
522 {
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700523 options[MOUNTABLE_COUNT + i] = mtds[i][0];
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700524 }
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700525
526 for (i = 0; i < MMC_COUNT; i++)
527 {
528 options[MOUNTABLE_COUNT + MTD_COUNT + i] = mmcs[i][0];
529 }
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700530
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700531 options[MOUNTABLE_COUNT + MTD_COUNT + MMC_COUNT] = "mount USB storage";
532 options[MOUNTABLE_COUNT + MTD_COUNT + MMC_COUNT + 1] = NULL;
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700533
534 int chosen_item = get_menu_selection(headers, options, 0);
535 if (chosen_item == GO_BACK)
536 break;
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700537 if (chosen_item == MOUNTABLE_COUNT + MTD_COUNT + MMC_COUNT)
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700538 {
539 show_mount_usb_storage_menu();
540 }
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700541 else if (chosen_item < MOUNTABLE_COUNT)
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700542 {
543 if (ismounted[chosen_item])
544 {
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700545 if (0 != ensure_root_path_unmounted(mounts[chosen_item][2]))
546 ui_print("Error unmounting %s!\n", mounts[chosen_item][2]);
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700547 }
548 else
549 {
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700550 if (0 != ensure_root_path_mounted(mounts[chosen_item][2]))
551 ui_print("Error mounting %s!\n", mounts[chosen_item][2]);
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700552 }
553 }
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700554 else if (chosen_item < MOUNTABLE_COUNT + MTD_COUNT)
555 {
556 chosen_item = chosen_item - MOUNTABLE_COUNT;
Koushik Duttaecd32fa2010-07-14 18:38:02 -0700557 if (!confirm_selection(confirm_format, confirm))
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700558 continue;
559 ui_print("Formatting %s...\n", mtds[chosen_item][1]);
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700560 if (0 != format_root_device(mtds[chosen_item][1]))
561 ui_print("Error formatting %s!\n", mtds[chosen_item][1]);
562 else
563 ui_print("Done.\n");
564 }
565 else if (chosen_item < MOUNTABLE_COUNT + MTD_COUNT + MMC_COUNT)
566 {
567 chosen_item = chosen_item - MOUNTABLE_COUNT - MTD_COUNT;
Koushik Duttaecd32fa2010-07-14 18:38:02 -0700568 if (!confirm_selection(confirm_format, confirm))
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700569 continue;
570 ui_print("Formatting %s...\n", mmcs[chosen_item][1]);
Koushik Dutta2f73e582010-04-18 16:00:21 -0700571 if (0 != format_non_mtd_device(mmcs[chosen_item][1]))
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700572 ui_print("Error formatting %s!\n", mmcs[chosen_item][1]);
573 else
574 ui_print("Done.\n");
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700575 }
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700576 }
577}
578
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800579#define EXTENDEDCOMMAND_SCRIPT "/cache/recovery/extendedcommand"
580
581int extendedcommand_file_exists()
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800582{
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800583 struct stat file_info;
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800584 return 0 == stat(EXTENDEDCOMMAND_SCRIPT, &file_info);
585}
586
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800587int run_script_from_buffer(char* script_data, int script_len, char* filename)
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800588{
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800589 /* Parse the script. Note that the script and parse tree are never freed.
590 */
591 const AmCommandList *commands = parseAmendScript(script_data, script_len);
592 if (commands == NULL) {
593 printf("Syntax error in update script\n");
594 return 1;
595 } else {
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800596 printf("Parsed %.*s\n", script_len, filename);
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800597 }
598
599 /* Execute the script.
600 */
601 int ret = execCommandList((ExecContext *)1, commands);
602 if (ret != 0) {
603 int num = ret;
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800604 char *line = NULL, *next = script_data;
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800605 while (next != NULL && ret-- > 0) {
606 line = next;
607 next = memchr(line, '\n', script_data + script_len - line);
608 if (next != NULL) *next++ = '\0';
609 }
610 printf("Failure at line %d:\n%s\n", num, next ? line : "(not found)");
611 return 1;
612 }
613
614 return 0;
615}
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800616
Koushik K. Dutta6771aca2010-04-03 23:28:39 -0700617int run_script(char* filename)
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800618{
619 struct stat file_info;
620 if (0 != stat(filename, &file_info)) {
621 printf("Error executing stat on file: %s\n", filename);
622 return 1;
623 }
624
625 int script_len = file_info.st_size;
Koushik K. Dutta707fa6d2010-03-23 11:44:33 -0700626 char* script_data = (char*)malloc(script_len + 1);
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800627 FILE *file = fopen(filename, "rb");
628 fread(script_data, script_len, 1, file);
Koushik K. Dutta707fa6d2010-03-23 11:44:33 -0700629 // supposedly not necessary, but let's be safe.
630 script_data[script_len] = '\0';
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800631 fclose(file);
Koushik Duttae25908b2010-06-21 08:16:19 -0700632 LOGI("Running script:\n");
633 LOGI("\n%s\n", script_data);
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800634
Koushik K. Duttaf3534d02010-04-18 18:06:24 -0700635 int ret = run_script_from_buffer(script_data, script_len, filename);
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700636 free(script_data);
637 return ret;
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800638}
639
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800640int run_and_remove_extendedcommand()
641{
Koushik K. Dutta6771aca2010-04-03 23:28:39 -0700642 char tmp[PATH_MAX];
643 sprintf(tmp, "cp %s /tmp/%s", EXTENDEDCOMMAND_SCRIPT, basename(EXTENDEDCOMMAND_SCRIPT));
644 __system(tmp);
645 remove(EXTENDEDCOMMAND_SCRIPT);
Koushik K. Dutta3a25cf52010-03-08 19:22:41 -0800646 int i = 0;
647 for (i = 20; i > 0; i--) {
648 ui_print("Waiting for SD Card to mount (%ds)\n", i);
649 if (ensure_root_path_mounted("SDCARD:") == 0) {
650 ui_print("SD Card mounted...\n");
651 break;
652 }
653 sleep(1);
654 }
Koushik Dutta92077c12010-07-15 00:10:08 -0700655 remove("/sdcard/clockworkmod/.recoverycheckpoint");
Koushik K. Dutta3a25cf52010-03-08 19:22:41 -0800656 if (i == 0) {
657 ui_print("Timed out waiting for SD card... continuing anyways.");
658 }
659
Koushik K. Dutta6771aca2010-04-03 23:28:39 -0700660 sprintf(tmp, "/tmp/%s", basename(EXTENDEDCOMMAND_SCRIPT));
661 return run_script(tmp);
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800662}
663
664int amend_main(int argc, char** argv)
665{
666 if (argc != 2)
667 {
668 printf("Usage: amend <script>\n");
669 return 0;
670 }
671
672 RecoveryCommandContext ctx = { NULL };
673 if (register_update_commands(&ctx)) {
674 LOGE("Can't install update commands\n");
675 }
Koushik K. Dutta6771aca2010-04-03 23:28:39 -0700676 return run_script(argv[1]);
Koushik K. Dutta5306db52010-03-08 14:09:35 -0800677}
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700678
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700679void show_nandroid_advanced_restore_menu()
680{
681 if (ensure_root_path_mounted("SDCARD:") != 0) {
682 LOGE ("Can't mount /sdcard\n");
683 return;
684 }
685
686 static char* advancedheaders[] = { "Choose an image to restore",
687 "",
688 "Choose an image to restore",
689 "first. The next menu will",
690 "you more options.",
691 "",
692 NULL
693 };
694
695 char* file = choose_file_menu("/sdcard/clockworkmod/backup/", NULL, advancedheaders);
696 if (file == NULL)
697 return;
698
699 static char* headers[] = { "Nandroid Advanced Restore",
700 "",
701 NULL
702 };
703
704 static char* list[] = { "Restore boot",
705 "Restore system",
706 "Restore data",
707 "Restore cache",
Koushik K. Dutta68b01902010-04-01 12:20:39 -0700708 "Restore sd-ext",
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700709 NULL
710 };
711
Koushik Duttad63eaef2010-07-14 21:01:21 -0700712
713 static char* confirm_restore = "Confirm restore?";
714
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700715 int chosen_item = get_menu_selection(headers, list, 0);
716 switch (chosen_item)
717 {
718 case 0:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700719 if (confirm_selection(confirm_restore, "Yes - Restore boot"))
720 nandroid_restore(file, 1, 0, 0, 0, 0);
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700721 break;
722 case 1:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700723 if (confirm_selection(confirm_restore, "Yes - Restore system"))
724 nandroid_restore(file, 0, 1, 0, 0, 0);
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700725 break;
726 case 2:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700727 if (confirm_selection(confirm_restore, "Yes - Restore data"))
728 nandroid_restore(file, 0, 0, 1, 0, 0);
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700729 break;
730 case 3:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700731 if (confirm_selection(confirm_restore, "Yes - Restore cache"))
732 nandroid_restore(file, 0, 0, 0, 1, 0);
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700733 break;
Koushik Dutta2f73e582010-04-18 16:00:21 -0700734 case 4:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700735 if (confirm_selection(confirm_restore, "Yes - Restore sd-ext"))
736 nandroid_restore(file, 0, 0, 0, 0, 1);
Koushik Dutta2f73e582010-04-18 16:00:21 -0700737 break;
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700738 }
739}
740
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700741void show_nandroid_menu()
742{
743 static char* headers[] = { "Nandroid",
744 "",
745 NULL
746 };
747
748 static char* list[] = { "Backup",
749 "Restore",
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700750 "Advanced Restore",
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700751 NULL
752 };
753
754 int chosen_item = get_menu_selection(headers, list, 0);
755 switch (chosen_item)
756 {
757 case 0:
758 {
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700759 char backup_path[PATH_MAX];
Koushik K. Dutta6a26e7c2010-03-27 15:26:11 -0700760 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 }
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700772 nandroid_backup(backup_path);
773 }
774 break;
775 case 1:
776 show_nandroid_restore_menu();
777 break;
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700778 case 2:
779 show_nandroid_advanced_restore_menu();
780 break;
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700781 }
Koushik K. Duttaa496b512010-03-19 14:51:45 -0700782}
783
Koushik Duttafd1579b2010-05-01 12:46:55 -0700784void wipe_battery_stats()
785{
786 ensure_root_path_mounted("DATA:");
787 remove("/data/system/batterystats.bin");
788 ensure_root_path_unmounted("DATA:");
789}
790
Koushik K. Duttaa496b512010-03-19 14:51:45 -0700791void show_advanced_menu()
792{
793 static char* headers[] = { "Advanced and Debugging Menu",
794 "",
795 NULL
796 };
797
Koushik K. Dutta7fe4d7b2010-04-06 23:04:52 -0700798 static char* list[] = { "Reboot Recovery",
Koushik Dutta49af23c2010-06-21 13:45:51 -0700799 "Wipe Dalvik Cache",
Koushik Duttafd1579b2010-05-01 12:46:55 -0700800 "Wipe Battery Stats",
Koushik Dutta598cfc72010-06-20 09:42:47 -0700801 "Report Error",
Koushik K. Dutta7fe4d7b2010-04-06 23:04:52 -0700802 "Key Test",
Koushik Duttae17a78d2010-08-29 12:35:10 -0700803#ifndef BOARD_HAS_SMALL_RECOVERY
Koushik Duttaceddcd52010-08-23 16:13:14 -0700804 "Partition SD Card",
805 "Fix Permissions",
Koushik Duttae17a78d2010-08-29 12:35:10 -0700806#endif
Koushik K. Duttaa496b512010-03-19 14:51:45 -0700807 NULL
808 };
809
810 for (;;)
811 {
812 int chosen_item = get_menu_selection(headers, list, 0);
813 if (chosen_item == GO_BACK)
814 break;
815 switch (chosen_item)
816 {
817 case 0:
Koushik K. Dutta7fe4d7b2010-04-06 23:04:52 -0700818 __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, "recovery");
819 break;
820 case 1:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700821 {
Koushik Dutta49af23c2010-06-21 13:45:51 -0700822 if (0 != ensure_root_path_mounted("DATA:"))
823 break;
Koushik Dutta6c7745d2010-08-07 12:17:13 -0700824 ensure_root_path_mounted("SDEXT:");
825 ensure_root_path_mounted("CACHE:");
826 if (confirm_selection( "Confirm wipe?", "Yes - Wipe Dalvik Cache")) {
Koushik Duttad63eaef2010-07-14 21:01:21 -0700827 __system("rm -r /data/dalvik-cache");
Koushik Dutta6c7745d2010-08-07 12:17:13 -0700828 __system("rm -r /cache/dalvik-cache");
829 __system("rm -r /sd-ext/dalvik-cache");
830 }
Koushik Dutta49af23c2010-06-21 13:45:51 -0700831 ensure_root_path_unmounted("DATA:");
Koushik Dutta6c7745d2010-08-07 12:17:13 -0700832 ui_print("Dalvik Cache wiped.\n");
Koushik Duttafd1579b2010-05-01 12:46:55 -0700833 break;
Koushik Duttad63eaef2010-07-14 21:01:21 -0700834 }
Koushik Duttafd1579b2010-05-01 12:46:55 -0700835 case 2:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700836 {
837 if (confirm_selection( "Confirm wipe?", "Yes - Wipe Battery Stats"))
838 wipe_battery_stats();
Koushik Dutta598cfc72010-06-20 09:42:47 -0700839 break;
Koushik Duttad63eaef2010-07-14 21:01:21 -0700840 }
Koushik Dutta598cfc72010-06-20 09:42:47 -0700841 case 3:
Koushik Dutta49af23c2010-06-21 13:45:51 -0700842 handle_failure(1);
843 break;
844 case 4:
Koushik K. Duttaa496b512010-03-19 14:51:45 -0700845 {
846 ui_print("Outputting key codes.\n");
847 ui_print("Go back to end debugging.\n");
848 int key;
849 int action;
850 do
851 {
852 key = ui_wait_key();
853 action = device_handle_key(key, 1);
854 ui_print("Key: %d\n", key);
855 }
856 while (action != GO_BACK);
Koushik Dutta56606a22010-08-23 16:15:33 -0700857 break;
Koushik K. Duttaa496b512010-03-19 14:51:45 -0700858 }
Koushik Duttaf0e31b82010-08-17 16:55:38 -0700859 case 5:
860 {
Koushik Duttaceddcd52010-08-23 16:13:14 -0700861 static char* ext_sizes[] = { "128M",
862 "256M",
863 "512M",
864 "1024M",
865 NULL };
866
867 static char* swap_sizes[] = { "0M",
868 "32M",
869 "64M",
870 "128M",
871 "256M",
872 NULL };
873
874 static char* ext_headers[] = { "Ext Size", "", NULL };
875 static char* swap_headers[] = { "Swap Size", "", NULL };
876
877 int ext_size = get_menu_selection(ext_headers, ext_sizes, 0);
878 if (ext_size == GO_BACK)
879 continue;
880
881 int swap_size = get_menu_selection(swap_headers, swap_sizes, 0);
882 if (swap_size == GO_BACK)
883 continue;
884
885 char sddevice[256];
886 const RootInfo *ri = get_root_info_for_path("SDCARD:");
887 strcpy(sddevice, ri->device);
888 // we only want the mmcblk, not the partition
889 sddevice[strlen("/dev/block/mmcblkX")] = NULL;
890 char cmd[PATH_MAX];
891 setenv("SDPATH", sddevice, 1);
892 sprintf(cmd, "sdparted -es %s -ss %s -efs ext3 -s", ext_sizes[ext_size], swap_sizes[swap_size]);
893 ui_print("Partitioning SD Card... please wait...\n");
894 if (0 == __system(cmd))
895 ui_print("Done!\n");
896 else
897 ui_print("An error occured while partitioning your SD Card. Please see /tmp/recovery.log for more details.\n");
Koushik Dutta56606a22010-08-23 16:15:33 -0700898 break;
Koushik Duttaf0e31b82010-08-17 16:55:38 -0700899 }
Koushik Dutta38e8b2b2010-08-17 22:21:53 -0700900 case 6:
901 {
Koushik Duttaceddcd52010-08-23 16:13:14 -0700902 ensure_root_path_mounted("SYSTEM:");
903 ensure_root_path_mounted("DATA:");
904 ui_print("Fixing permissions...\n");
905 __system("fix_permissions");
906 ui_print("Done!\n");
Koushik Dutta56606a22010-08-23 16:15:33 -0700907 break;
Koushik Dutta38e8b2b2010-08-17 22:21:53 -0700908 }
Koushik K. Duttaa496b512010-03-19 14:51:45 -0700909 }
910 }
Koushik Dutta14239d22010-06-14 15:02:48 -0700911}
912
913void write_fstab_root(char *root_path, FILE *file)
914{
915 RootInfo *info = get_root_info_for_path(root_path);
Koushik Duttaa6522b32010-06-20 13:16:06 -0700916 if (info == NULL) {
917 LOGW("Unable to get root info for %s during fstab generation!", root_path);
Koushik Dutta598cfc72010-06-20 09:42:47 -0700918 return;
Koushik Duttaa6522b32010-06-20 13:16:06 -0700919 }
Koushik Dutta14239d22010-06-14 15:02:48 -0700920 MtdPartition *mtd = get_root_mtd_partition(root_path);
921 if (mtd != NULL)
922 {
923 fprintf(file, "/dev/block/mtdblock%d ", mtd->device_index);
924 }
925 else
926 {
Koushik Dutta4233c7f2010-09-03 22:16:57 -0700927 fprintf(file, "%s ", info->device);
Koushik Dutta14239d22010-06-14 15:02:48 -0700928 }
929
930 fprintf(file, "%s ", info->mount_point);
Koushik Duttad4060c32010-07-22 20:14:44 -0700931 fprintf(file, "%s %s\n", info->filesystem, info->filesystem_options == NULL ? "rw" : info->filesystem_options);
Koushik Dutta14239d22010-06-14 15:02:48 -0700932}
933
934void create_fstab()
935{
Koushik Duttacd44ab92010-06-23 00:02:14 -0700936 __system("touch /etc/mtab");
Koushik Dutta14239d22010-06-14 15:02:48 -0700937 FILE *file = fopen("/etc/fstab", "w");
Koushik Duttaa6522b32010-06-20 13:16:06 -0700938 if (file == NULL) {
939 LOGW("Unable to create /etc/fstab!");
Koushik Dutta598cfc72010-06-20 09:42:47 -0700940 return;
Koushik Duttaa6522b32010-06-20 13:16:06 -0700941 }
Koushik Dutta14239d22010-06-14 15:02:48 -0700942 write_fstab_root("CACHE:", file);
943 write_fstab_root("DATA:", file);
Koushik Duttaa6522b32010-06-20 13:16:06 -0700944#ifdef HAS_DATADATA
945 write_fstab_root("DATADATA:", file);
946#endif
Koushik Dutta14239d22010-06-14 15:02:48 -0700947 write_fstab_root("SYSTEM:", file);
948 write_fstab_root("SDCARD:", file);
949 write_fstab_root("SDEXT:", file);
950 fclose(file);
Koushik Dutta598cfc72010-06-20 09:42:47 -0700951}
952
953void handle_failure(int ret)
954{
955 if (ret == 0)
956 return;
957 if (0 != ensure_root_path_mounted("SDCARD:"))
958 return;
Koushik Duttaa6522b32010-06-20 13:16:06 -0700959 mkdir("/sdcard/clockworkmod", S_IRWXU);
960 __system("cp /tmp/recovery.log /sdcard/clockworkmod/recovery.log");
Koushik Dutta38e8b2b2010-08-17 22:21:53 -0700961 ui_print("/tmp/recovery.log was copied to /sdcard/clockworkmod/recovery.log. Please open ROM Manager to report the issue.\n");
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700962}