blob: 801f4a86187fbf1d3518ef170e898c2d05f8645e [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 K. Duttaa85d7cc2010-03-12 17:00:58 -080036#include "../../external/yaffs2/yaffs2/utils/mkyaffs2image.h"
Koushik K. Dutta54305a82010-03-12 17:43:26 -080037#include "../../external/yaffs2/yaffs2/utils/unyaffs.h"
Koushik K. Duttaa85d7cc2010-03-12 17:00:58 -080038
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -080039#include "extendedcommands.h"
40#include "nandroid.h"
41
Koushik K. Dutta6060e5c2010-02-11 22:27:06 -080042int signature_check_enabled = 1;
43int script_assert_enabled = 1;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080044static const char *SDCARD_PACKAGE_FILE = "SDCARD:update.zip";
Koushik K. Dutta6060e5c2010-02-11 22:27:06 -080045
46void
47toggle_signature_check()
48{
49 signature_check_enabled = !signature_check_enabled;
50 ui_print("Signature Check: %s\n", signature_check_enabled ? "Enabled" : "Disabled");
51}
52
53void toggle_script_asserts()
54{
55 script_assert_enabled = !script_assert_enabled;
Koushik K. Duttae9234872010-02-12 00:43:24 -080056 ui_print("Script Asserts: %s\n", script_assert_enabled ? "Enabled" : "Disabled");
57}
58
Koushik K. Duttaea46fe22010-03-08 02:58:04 -080059int install_zip(const char* packagefilepath)
Koushik K. Duttae9234872010-02-12 00:43:24 -080060{
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080061 ui_print("\n-- Installing: %s\n", packagefilepath);
Koushik Dutta5aaa8232010-07-20 16:23:18 -070062#ifndef BOARD_HAS_NO_MISC_PARTITION
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080063 set_sdcard_update_bootloader_message();
Koushik Dutta5aaa8232010-07-20 16:23:18 -070064#endif
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080065 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 }
Koushik Dutta5aaa8232010-07-20 16:23:18 -070072#ifndef BOARD_HAS_NO_MISC_PARTITION
Koushik K. Dutta79ce82c2010-02-25 12:03:17 -080073 if (firmware_update_pending()) {
74 ui_print("\nReboot via menu to complete\ninstallation.\n");
Koushik K. Dutta001c5b52010-02-25 14:53:57 -080075 }
Koushik Dutta5aaa8232010-07-20 16:23:18 -070076#endif
Koushik K. Dutta001c5b52010-02-25 14:53:57 -080077 ui_set_background(BACKGROUND_ICON_NONE);
Koushik K. Dutta99fb6fe2010-03-03 00:42:58 -080078 ui_print("\nInstall from sdcard complete.\n");
Koushik K. Duttaea46fe22010-03-08 02:58:04 -080079 return 0;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080080}
81
82char* INSTALL_MENU_ITEMS[] = { "apply sdcard:update.zip",
83 "choose zip from sdcard",
84 "toggle signature verification",
85 "toggle script asserts",
86 NULL };
87#define ITEM_APPLY_SDCARD 0
88#define ITEM_CHOOSE_ZIP 1
89#define ITEM_SIG_CHECK 2
90#define ITEM_ASSERTS 3
91
92void show_install_update_menu()
93{
94 static char* headers[] = { "Apply update from .zip file on SD card",
95 "",
96 NULL
97 };
98 for (;;)
99 {
100 int chosen_item = get_menu_selection(headers, INSTALL_MENU_ITEMS, 0);
101 switch (chosen_item)
102 {
103 case ITEM_ASSERTS:
104 toggle_script_asserts();
105 break;
106 case ITEM_SIG_CHECK:
107 toggle_signature_check();
108 break;
109 case ITEM_APPLY_SDCARD:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700110 {
111 if (confirm_selection("Confirm install?", "Yes - Install /sdcard/update.zip"))
112 install_zip(SDCARD_PACKAGE_FILE);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800113 break;
Koushik Duttad63eaef2010-07-14 21:01:21 -0700114 }
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800115 case ITEM_CHOOSE_ZIP:
116 show_choose_zip_menu();
117 break;
118 default:
119 return;
120 }
121
122 }
123}
124
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700125void free_string_array(char** array)
126{
127 if (array == NULL)
128 return;
129 char* cursor = array[0];
130 int i = 0;
131 while (cursor != NULL)
132 {
133 free(cursor);
134 cursor = array[++i];
135 }
136 free(array);
137}
138
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800139char** gather_files(const char* directory, const char* fileExtensionOrDirectory, int* numFiles)
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800140{
Koushik K. Duttae9234872010-02-12 00:43:24 -0800141 char path[PATH_MAX] = "";
142 DIR *dir;
143 struct dirent *de;
144 int total = 0;
145 int i;
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800146 char** files = NULL;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800147 int pass;
148 *numFiles = 0;
149 int dirLen = strlen(directory);
Koushik K. Duttae9234872010-02-12 00:43:24 -0800150
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800151 dir = opendir(directory);
152 if (dir == NULL) {
153 ui_print("Couldn't open directory.\n");
154 return NULL;
155 }
156
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800157 int extension_length = 0;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800158 if (fileExtensionOrDirectory != NULL)
159 extension_length = strlen(fileExtensionOrDirectory);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800160
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800161 int isCounting = 1;
162 i = 0;
163 for (pass = 0; pass < 2; pass++) {
164 while ((de=readdir(dir)) != NULL) {
165 // skip hidden files
166 if (de->d_name[0] == '.')
167 continue;
168
169 // NULL means that we are gathering directories, so skip this
170 if (fileExtensionOrDirectory != NULL)
171 {
172 // make sure that we can have the desired extension (prevent seg fault)
173 if (strlen(de->d_name) < extension_length)
174 continue;
175 // compare the extension
176 if (strcmp(de->d_name + strlen(de->d_name) - extension_length, fileExtensionOrDirectory) != 0)
177 continue;
178 }
179 else
180 {
181 struct stat info;
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700182 char fullFileName[PATH_MAX];
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800183 strcpy(fullFileName, directory);
184 strcat(fullFileName, de->d_name);
185 stat(fullFileName, &info);
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800186 // make sure it is a directory
187 if (!(S_ISDIR(info.st_mode)))
188 continue;
189 }
190
191 if (pass == 0)
192 {
193 total++;
194 continue;
195 }
196
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800197 files[i] = (char*) malloc(dirLen + strlen(de->d_name) + 2);
198 strcpy(files[i], directory);
199 strcat(files[i], de->d_name);
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800200 if (fileExtensionOrDirectory == NULL)
201 strcat(files[i], "/");
202 i++;
203 }
204 if (pass == 1)
205 break;
206 if (total == 0)
207 break;
208 rewinddir(dir);
209 *numFiles = total;
210 files = (char**) malloc((total+1)*sizeof(char*));
211 files[total]=NULL;
212 }
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800213
214 if(closedir(dir) < 0) {
215 LOGE("Failed to close directory.");
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800216 }
217
218 if (total==0) {
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800219 return NULL;
220 }
221
Koushik Dutta1e8aaba2010-07-01 00:23:25 -0700222 // sort the result
223 if (files != NULL) {
224 for (i = 0; i < total; i++) {
225 int curMax = -1;
226 int j;
227 for (j = 0; j < total - i; j++) {
228 if (curMax == -1 || strcmp(files[curMax], files[j]) < 0)
229 curMax = j;
230 }
231 char* temp = files[curMax];
232 files[curMax] = files[total - i - 1];
233 files[total - i - 1] = temp;
234 }
235 }
236
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800237 return files;
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800238}
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800239
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800240// pass in NULL for fileExtensionOrDirectory and you will get a directory chooser
241char* choose_file_menu(const char* directory, const char* fileExtensionOrDirectory, const char* headers[])
242{
243 char path[PATH_MAX] = "";
244 DIR *dir;
245 struct dirent *de;
246 int numFiles = 0;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800247 int numDirs = 0;
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800248 int i;
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700249 char* return_value = NULL;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800250 int dir_len = strlen(directory);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800251
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800252 char** files = gather_files(directory, fileExtensionOrDirectory, &numFiles);
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800253 char** dirs = NULL;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800254 if (fileExtensionOrDirectory != NULL)
255 dirs = gather_files(directory, NULL, &numDirs);
256 int total = numDirs + numFiles;
257 if (total == 0)
258 {
259 ui_print("No files found.\n");
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800260 }
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700261 else
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800262 {
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700263 char** list = (char**) malloc((total + 1) * sizeof(char*));
264 list[total] = NULL;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800265
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800266
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700267 for (i = 0 ; i < numDirs; i++)
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800268 {
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700269 list[i] = strdup(dirs[i] + dir_len);
270 }
271
272 for (i = 0 ; i < numFiles; i++)
273 {
274 list[numDirs + i] = strdup(files[i] + dir_len);
275 }
276
277 for (;;)
278 {
279 int chosen_item = get_menu_selection(headers, list, 0);
280 if (chosen_item == GO_BACK)
281 break;
282 static char ret[PATH_MAX];
283 if (chosen_item < numDirs)
284 {
285 char* subret = choose_file_menu(dirs[chosen_item], fileExtensionOrDirectory, headers);
286 if (subret != NULL)
287 {
288 strcpy(ret, subret);
289 return_value = ret;
290 break;
291 }
292 continue;
293 }
294 strcpy(ret, files[chosen_item - numDirs]);
295 return_value = ret;
296 break;
297 }
298 free_string_array(list);
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800299 }
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700300
301 free_string_array(files);
302 free_string_array(dirs);
303 return return_value;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800304}
305
306void show_choose_zip_menu()
307{
Koushik K. Duttae9234872010-02-12 00:43:24 -0800308 if (ensure_root_path_mounted("SDCARD:") != 0) {
309 LOGE ("Can't mount /sdcard\n");
310 return;
311 }
312
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800313 static char* headers[] = { "Choose a zip to apply",
314 "",
315 NULL
316 };
317
318 char* file = choose_file_menu("/sdcard/", ".zip", headers);
319 if (file == NULL)
320 return;
321 char sdcard_package_file[1024];
322 strcpy(sdcard_package_file, "SDCARD:");
323 strcat(sdcard_package_file, file + strlen("/sdcard/"));
Koushik Duttad63eaef2010-07-14 21:01:21 -0700324 static char* confirm_install = "Confirm install?";
325 static char confirm[PATH_MAX];
326 sprintf(confirm, "Yes - Install %s", basename(file));
327 if (confirm_selection(confirm_install, confirm))
328 install_zip(sdcard_package_file);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800329}
330
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800331// This was pulled from bionic: The default system command always looks
332// for shell in /system/bin/sh. This is bad.
333#define _PATH_BSHELL "/sbin/sh"
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800334
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800335extern char **environ;
336int
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800337__system(const char *command)
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800338{
339 pid_t pid;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800340 sig_t intsave, quitsave;
341 sigset_t mask, omask;
342 int pstat;
343 char *argp[] = {"sh", "-c", NULL, NULL};
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800344
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800345 if (!command) /* just checking... */
346 return(1);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800347
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800348 argp[2] = (char *)command;
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800349
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800350 sigemptyset(&mask);
351 sigaddset(&mask, SIGCHLD);
352 sigprocmask(SIG_BLOCK, &mask, &omask);
353 switch (pid = vfork()) {
354 case -1: /* error */
355 sigprocmask(SIG_SETMASK, &omask, NULL);
356 return(-1);
357 case 0: /* child */
358 sigprocmask(SIG_SETMASK, &omask, NULL);
359 execve(_PATH_BSHELL, argp, environ);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800360 _exit(127);
361 }
362
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800363 intsave = (sig_t) bsd_signal(SIGINT, SIG_IGN);
364 quitsave = (sig_t) bsd_signal(SIGQUIT, SIG_IGN);
365 pid = waitpid(pid, (int *)&pstat, 0);
366 sigprocmask(SIG_SETMASK, &omask, NULL);
367 (void)bsd_signal(SIGINT, intsave);
368 (void)bsd_signal(SIGQUIT, quitsave);
369 return (pid == -1 ? -1 : pstat);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800370}
371
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800372void show_nandroid_restore_menu()
373{
Koushik K. Dutta54305a82010-03-12 17:43:26 -0800374 if (ensure_root_path_mounted("SDCARD:") != 0) {
375 LOGE ("Can't mount /sdcard\n");
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800376 return;
Koushik K. Dutta54305a82010-03-12 17:43:26 -0800377 }
378
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800379 static char* headers[] = { "Choose an image to restore",
380 "",
381 NULL
382 };
Koushik K. Duttae9234872010-02-12 00:43:24 -0800383
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800384 char* file = choose_file_menu("/sdcard/clockworkmod/backup/", NULL, headers);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800385 if (file == NULL)
386 return;
Koushik Duttad63eaef2010-07-14 21:01:21 -0700387
388 if (confirm_selection("Confirm restore?", "Yes - Restore"))
389 nandroid_restore(file, 1, 1, 1, 1, 1);
Koushik K. Dutta03173782010-02-26 14:14:23 -0800390}
391
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700392void show_mount_usb_storage_menu()
Koushik K. Dutta03173782010-02-26 14:14:23 -0800393{
Koushik Dutta598cfc72010-06-20 09:42:47 -0700394 char command[PATH_MAX];
Koushik Dutta19447c02010-11-10 10:40:44 -0800395 sprintf(command, "echo %s > /sys/devices/platform/usb_mass_storage/lun0/file", BOARD_SDCARD_DEVICE_PRIMARY);
Koushik Dutta598cfc72010-06-20 09:42:47 -0700396 __system(command);
Koushik K. Dutta03173782010-02-26 14:14:23 -0800397 static char* headers[] = { "USB Mass Storage device",
398 "Leaving this menu unmount",
399 "your SD card from your PC.",
400 "",
401 NULL
402 };
403
404 static char* list[] = { "Unmount", NULL };
405
406 for (;;)
407 {
408 int chosen_item = get_menu_selection(headers, list, 0);
409 if (chosen_item == GO_BACK || chosen_item == 0)
410 break;
411 }
412
Koushik K. Duttaf7215942010-03-16 13:34:51 -0700413 __system("echo '' > /sys/devices/platform/usb_mass_storage/lun0/file");
414 __system("echo 0 > /sys/devices/platform/usb_mass_storage/lun0/enable");
Koushik K. Duttae81cb752010-02-26 17:44:33 -0800415}
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800416
Koushik Duttad63eaef2010-07-14 21:01:21 -0700417int confirm_selection(const char* title, const char* confirm)
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700418{
Koushik Duttaceddcd52010-08-23 16:13:14 -0700419 struct stat info;
420 if (0 == stat("/sdcard/clockworkmod/.no_confirm", &info))
421 return 1;
422
Koushik Duttad63eaef2010-07-14 21:01:21 -0700423 char* confirm_headers[] = { title, " THIS CAN NOT BE UNDONE.", "", NULL };
424 char* items[] = { "No",
425 "No",
426 "No",
427 "No",
428 "No",
429 "No",
430 "No",
Koushik Duttaecd32fa2010-07-14 18:38:02 -0700431 confirm, //" Yes -- wipe partition", // [7
Koushik Duttad63eaef2010-07-14 21:01:21 -0700432 "No",
433 "No",
434 "No",
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700435 NULL };
436
Koushik Duttad63eaef2010-07-14 21:01:21 -0700437 int chosen_item = get_menu_selection(confirm_headers, items, 0);
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700438 return chosen_item == 7;
439}
440
Koushik Dutta19447c02010-11-10 10:40:44 -0800441int format_unknown_device(const char* root)
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700442{
Koushik K. Duttaf3534d02010-04-18 18:06:24 -0700443 // if this is SDEXT:, don't worry about it.
444 if (0 == strcmp(root, "SDEXT:"))
445 {
446 struct stat st;
Koushik Dutta19447c02010-11-10 10:40:44 -0800447 if (0 != stat(BOARD_SDEXT_DEVICE, &st))
Koushik K. Duttaf3534d02010-04-18 18:06:24 -0700448 {
449 ui_print("No app2sd partition found. Skipping format of /sd-ext.\n");
450 return 0;
451 }
452 }
Koushik Dutta2f73e582010-04-18 16:00:21 -0700453
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700454 char path[PATH_MAX];
455 translate_root_path(root, path, PATH_MAX);
456 if (0 != ensure_root_path_mounted(root))
457 {
458 ui_print("Error mounting %s!\n", path);
Koushik Duttacd44ab92010-06-23 00:02:14 -0700459 ui_print("Skipping format...\n");
460 return 0;
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700461 }
462
463 static char tmp[PATH_MAX];
464 sprintf(tmp, "rm -rf %s/*", path);
465 __system(tmp);
466 sprintf(tmp, "rm -rf %s/.*", path);
467 __system(tmp);
468
469 ensure_root_path_unmounted(root);
470 return 0;
471}
472
473#define MOUNTABLE_COUNT 5
474#define MTD_COUNT 4
475#define MMC_COUNT 2
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700476
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700477void show_partition_menu()
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700478{
Koushik Duttaceddcd52010-08-23 16:13:14 -0700479 static char* headers[] = { "Mounts and Storage Menu",
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700480 "",
481 NULL
482 };
483
484 typedef char* string;
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700485 string mounts[MOUNTABLE_COUNT][3] = {
486 { "mount /system", "unmount /system", "SYSTEM:" },
487 { "mount /data", "unmount /data", "DATA:" },
488 { "mount /cache", "unmount /cache", "CACHE:" },
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700489 { "mount /sdcard", "unmount /sdcard", "SDCARD:" },
490 { "mount /sd-ext", "unmount /sd-ext", "SDEXT:" }
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700491 };
492
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700493 string mtds[MTD_COUNT][2] = {
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700494 { "format boot", "BOOT:" },
495 { "format system", "SYSTEM:" },
496 { "format data", "DATA:" },
497 { "format cache", "CACHE:" },
498 };
499
500 string mmcs[MMC_COUNT][3] = {
501 { "format sdcard", "SDCARD:" },
Koushik K. Duttaa5f64e62010-04-05 15:44:57 -0700502 { "format sd-ext", "SDEXT:" }
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700503 };
Koushik Duttaecd32fa2010-07-14 18:38:02 -0700504
Koushik Duttad63eaef2010-07-14 21:01:21 -0700505 static char* confirm_format = "Confirm format?";
Koushik Duttaecd32fa2010-07-14 18:38:02 -0700506 static char* confirm = "Yes - Format";
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700507
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700508 for (;;)
509 {
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700510 int ismounted[MOUNTABLE_COUNT];
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700511 int i;
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700512 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 -0700513 for (i = 0; i < MOUNTABLE_COUNT; i++)
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700514 {
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700515 ismounted[i] = is_root_path_mounted(mounts[i][2]);
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700516 options[i] = ismounted[i] ? mounts[i][1] : mounts[i][0];
517 }
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700518
519 for (i = 0; i < MTD_COUNT; i++)
520 {
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700521 options[MOUNTABLE_COUNT + i] = mtds[i][0];
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700522 }
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700523
524 for (i = 0; i < MMC_COUNT; i++)
525 {
526 options[MOUNTABLE_COUNT + MTD_COUNT + i] = mmcs[i][0];
527 }
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700528
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700529 options[MOUNTABLE_COUNT + MTD_COUNT + MMC_COUNT] = "mount USB storage";
530 options[MOUNTABLE_COUNT + MTD_COUNT + MMC_COUNT + 1] = NULL;
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700531
532 int chosen_item = get_menu_selection(headers, options, 0);
533 if (chosen_item == GO_BACK)
534 break;
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700535 if (chosen_item == MOUNTABLE_COUNT + MTD_COUNT + MMC_COUNT)
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700536 {
537 show_mount_usb_storage_menu();
538 }
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700539 else if (chosen_item < MOUNTABLE_COUNT)
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700540 {
541 if (ismounted[chosen_item])
542 {
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700543 if (0 != ensure_root_path_unmounted(mounts[chosen_item][2]))
544 ui_print("Error unmounting %s!\n", mounts[chosen_item][2]);
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700545 }
546 else
547 {
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700548 if (0 != ensure_root_path_mounted(mounts[chosen_item][2]))
549 ui_print("Error mounting %s!\n", mounts[chosen_item][2]);
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700550 }
551 }
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700552 else if (chosen_item < MOUNTABLE_COUNT + MTD_COUNT)
553 {
554 chosen_item = chosen_item - MOUNTABLE_COUNT;
Koushik Duttaecd32fa2010-07-14 18:38:02 -0700555 if (!confirm_selection(confirm_format, confirm))
Koushik K. Dutta16f0b492010-03-19 14:37:11 -0700556 continue;
557 ui_print("Formatting %s...\n", mtds[chosen_item][1]);
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700558 if (0 != format_root_device(mtds[chosen_item][1]))
559 ui_print("Error formatting %s!\n", mtds[chosen_item][1]);
560 else
561 ui_print("Done.\n");
562 }
563 else if (chosen_item < MOUNTABLE_COUNT + MTD_COUNT + MMC_COUNT)
564 {
565 chosen_item = chosen_item - MOUNTABLE_COUNT - MTD_COUNT;
Koushik Duttaecd32fa2010-07-14 18:38:02 -0700566 if (!confirm_selection(confirm_format, confirm))
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700567 continue;
568 ui_print("Formatting %s...\n", mmcs[chosen_item][1]);
Koushik Dutta19447c02010-11-10 10:40:44 -0800569 if (0 != format_unknown_device(mmcs[chosen_item][1]))
Koushik K. Dutta3f995392010-03-30 23:29:43 -0700570 ui_print("Error formatting %s!\n", mmcs[chosen_item][1]);
571 else
572 ui_print("Done.\n");
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700573 }
Koushik K. Duttab9546a82010-03-14 22:42:30 -0700574 }
575}
576
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800577#define EXTENDEDCOMMAND_SCRIPT "/cache/recovery/extendedcommand"
578
579int extendedcommand_file_exists()
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800580{
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800581 struct stat file_info;
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800582 return 0 == stat(EXTENDEDCOMMAND_SCRIPT, &file_info);
583}
584
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800585int run_script_from_buffer(char* script_data, int script_len, char* filename)
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800586{
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800587 /* Parse the script. Note that the script and parse tree are never freed.
588 */
589 const AmCommandList *commands = parseAmendScript(script_data, script_len);
590 if (commands == NULL) {
591 printf("Syntax error in update script\n");
592 return 1;
593 } else {
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800594 printf("Parsed %.*s\n", script_len, filename);
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800595 }
596
597 /* Execute the script.
598 */
599 int ret = execCommandList((ExecContext *)1, commands);
600 if (ret != 0) {
601 int num = ret;
Koushik K. Duttaee57bbc2010-03-12 23:21:12 -0800602 char *line = NULL, *next = script_data;
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800603 while (next != NULL && ret-- > 0) {
604 line = next;
605 next = memchr(line, '\n', script_data + script_len - line);
606 if (next != NULL) *next++ = '\0';
607 }
608 printf("Failure at line %d:\n%s\n", num, next ? line : "(not found)");
609 return 1;
610 }
611
612 return 0;
613}
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800614
Koushik K. Dutta6771aca2010-04-03 23:28:39 -0700615int run_script(char* filename)
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800616{
617 struct stat file_info;
618 if (0 != stat(filename, &file_info)) {
619 printf("Error executing stat on file: %s\n", filename);
620 return 1;
621 }
622
623 int script_len = file_info.st_size;
Koushik K. Dutta707fa6d2010-03-23 11:44:33 -0700624 char* script_data = (char*)malloc(script_len + 1);
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800625 FILE *file = fopen(filename, "rb");
626 fread(script_data, script_len, 1, file);
Koushik K. Dutta707fa6d2010-03-23 11:44:33 -0700627 // supposedly not necessary, but let's be safe.
628 script_data[script_len] = '\0';
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800629 fclose(file);
Koushik Duttae25908b2010-06-21 08:16:19 -0700630 LOGI("Running script:\n");
631 LOGI("\n%s\n", script_data);
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800632
Koushik K. Duttaf3534d02010-04-18 18:06:24 -0700633 int ret = run_script_from_buffer(script_data, script_len, filename);
Koushik K. Dutta1d53c4e2010-04-02 16:46:21 -0700634 free(script_data);
635 return ret;
Koushik K. Dutta3836f722010-03-11 22:17:43 -0800636}
637
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800638int run_and_remove_extendedcommand()
639{
Koushik K. Dutta6771aca2010-04-03 23:28:39 -0700640 char tmp[PATH_MAX];
641 sprintf(tmp, "cp %s /tmp/%s", EXTENDEDCOMMAND_SCRIPT, basename(EXTENDEDCOMMAND_SCRIPT));
642 __system(tmp);
643 remove(EXTENDEDCOMMAND_SCRIPT);
Koushik K. Dutta3a25cf52010-03-08 19:22:41 -0800644 int i = 0;
645 for (i = 20; i > 0; i--) {
646 ui_print("Waiting for SD Card to mount (%ds)\n", i);
647 if (ensure_root_path_mounted("SDCARD:") == 0) {
648 ui_print("SD Card mounted...\n");
649 break;
650 }
651 sleep(1);
652 }
Koushik Dutta92077c12010-07-15 00:10:08 -0700653 remove("/sdcard/clockworkmod/.recoverycheckpoint");
Koushik K. Dutta3a25cf52010-03-08 19:22:41 -0800654 if (i == 0) {
655 ui_print("Timed out waiting for SD card... continuing anyways.");
656 }
657
Koushik K. Dutta6771aca2010-04-03 23:28:39 -0700658 sprintf(tmp, "/tmp/%s", basename(EXTENDEDCOMMAND_SCRIPT));
659 return run_script(tmp);
Koushik K. Dutta72a1db62010-03-07 14:10:26 -0800660}
661
662int amend_main(int argc, char** argv)
663{
664 if (argc != 2)
665 {
666 printf("Usage: amend <script>\n");
667 return 0;
668 }
669
670 RecoveryCommandContext ctx = { NULL };
671 if (register_update_commands(&ctx)) {
672 LOGE("Can't install update commands\n");
673 }
Koushik K. Dutta6771aca2010-04-03 23:28:39 -0700674 return run_script(argv[1]);
Koushik K. Dutta5306db52010-03-08 14:09:35 -0800675}
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700676
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700677void show_nandroid_advanced_restore_menu()
678{
679 if (ensure_root_path_mounted("SDCARD:") != 0) {
680 LOGE ("Can't mount /sdcard\n");
681 return;
682 }
683
684 static char* advancedheaders[] = { "Choose an image to restore",
685 "",
686 "Choose an image to restore",
687 "first. The next menu will",
688 "you more options.",
689 "",
690 NULL
691 };
692
693 char* file = choose_file_menu("/sdcard/clockworkmod/backup/", NULL, advancedheaders);
694 if (file == NULL)
695 return;
696
697 static char* headers[] = { "Nandroid Advanced Restore",
698 "",
699 NULL
700 };
701
702 static char* list[] = { "Restore boot",
703 "Restore system",
704 "Restore data",
705 "Restore cache",
Koushik K. Dutta68b01902010-04-01 12:20:39 -0700706 "Restore sd-ext",
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700707 NULL
708 };
709
Koushik Duttad63eaef2010-07-14 21:01:21 -0700710
711 static char* confirm_restore = "Confirm restore?";
712
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700713 int chosen_item = get_menu_selection(headers, list, 0);
714 switch (chosen_item)
715 {
716 case 0:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700717 if (confirm_selection(confirm_restore, "Yes - Restore boot"))
718 nandroid_restore(file, 1, 0, 0, 0, 0);
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700719 break;
720 case 1:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700721 if (confirm_selection(confirm_restore, "Yes - Restore system"))
722 nandroid_restore(file, 0, 1, 0, 0, 0);
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700723 break;
724 case 2:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700725 if (confirm_selection(confirm_restore, "Yes - Restore data"))
726 nandroid_restore(file, 0, 0, 1, 0, 0);
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700727 break;
728 case 3:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700729 if (confirm_selection(confirm_restore, "Yes - Restore cache"))
730 nandroid_restore(file, 0, 0, 0, 1, 0);
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700731 break;
Koushik Dutta2f73e582010-04-18 16:00:21 -0700732 case 4:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700733 if (confirm_selection(confirm_restore, "Yes - Restore sd-ext"))
734 nandroid_restore(file, 0, 0, 0, 0, 1);
Koushik Dutta2f73e582010-04-18 16:00:21 -0700735 break;
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700736 }
737}
738
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700739void show_nandroid_menu()
740{
741 static char* headers[] = { "Nandroid",
742 "",
743 NULL
744 };
745
746 static char* list[] = { "Backup",
747 "Restore",
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700748 "Advanced Restore",
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700749 NULL
750 };
751
752 int chosen_item = get_menu_selection(headers, list, 0);
753 switch (chosen_item)
754 {
755 case 0:
756 {
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700757 char backup_path[PATH_MAX];
Koushik K. Dutta6a26e7c2010-03-27 15:26:11 -0700758 time_t t = time(NULL);
759 struct tm *tmp = localtime(&t);
760 if (tmp == NULL)
761 {
762 struct timeval tp;
763 gettimeofday(&tp, NULL);
764 sprintf(backup_path, "/sdcard/clockworkmod/backup/%d", tp.tv_sec);
765 }
766 else
767 {
768 strftime(backup_path, sizeof(backup_path), "/sdcard/clockworkmod/backup/%F.%H.%M.%S", tmp);
769 }
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700770 nandroid_backup(backup_path);
771 }
772 break;
773 case 1:
774 show_nandroid_restore_menu();
775 break;
Koushik K. Duttafe84a7f2010-03-25 18:19:23 -0700776 case 2:
777 show_nandroid_advanced_restore_menu();
778 break;
Koushik K. Dutta5899ac92010-03-19 13:34:36 -0700779 }
Koushik K. Duttaa496b512010-03-19 14:51:45 -0700780}
781
Koushik Duttafd1579b2010-05-01 12:46:55 -0700782void wipe_battery_stats()
783{
784 ensure_root_path_mounted("DATA:");
785 remove("/data/system/batterystats.bin");
786 ensure_root_path_unmounted("DATA:");
787}
788
Koushik K. Duttaa496b512010-03-19 14:51:45 -0700789void show_advanced_menu()
790{
791 static char* headers[] = { "Advanced and Debugging Menu",
792 "",
793 NULL
794 };
795
Koushik K. Dutta7fe4d7b2010-04-06 23:04:52 -0700796 static char* list[] = { "Reboot Recovery",
Koushik Dutta49af23c2010-06-21 13:45:51 -0700797 "Wipe Dalvik Cache",
Koushik Duttafd1579b2010-05-01 12:46:55 -0700798 "Wipe Battery Stats",
Koushik Dutta598cfc72010-06-20 09:42:47 -0700799 "Report Error",
Koushik K. Dutta7fe4d7b2010-04-06 23:04:52 -0700800 "Key Test",
Koushik Duttae17a78d2010-08-29 12:35:10 -0700801#ifndef BOARD_HAS_SMALL_RECOVERY
Koushik Duttaceddcd52010-08-23 16:13:14 -0700802 "Partition SD Card",
803 "Fix Permissions",
Koushik Duttae17a78d2010-08-29 12:35:10 -0700804#endif
Koushik K. Duttaa496b512010-03-19 14:51:45 -0700805 NULL
806 };
807
808 for (;;)
809 {
810 int chosen_item = get_menu_selection(headers, list, 0);
811 if (chosen_item == GO_BACK)
812 break;
813 switch (chosen_item)
814 {
815 case 0:
Koushik K. Dutta7fe4d7b2010-04-06 23:04:52 -0700816 __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, "recovery");
817 break;
818 case 1:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700819 {
Koushik Dutta49af23c2010-06-21 13:45:51 -0700820 if (0 != ensure_root_path_mounted("DATA:"))
821 break;
Koushik Dutta6c7745d2010-08-07 12:17:13 -0700822 ensure_root_path_mounted("SDEXT:");
823 ensure_root_path_mounted("CACHE:");
824 if (confirm_selection( "Confirm wipe?", "Yes - Wipe Dalvik Cache")) {
Koushik Duttad63eaef2010-07-14 21:01:21 -0700825 __system("rm -r /data/dalvik-cache");
Koushik Dutta6c7745d2010-08-07 12:17:13 -0700826 __system("rm -r /cache/dalvik-cache");
827 __system("rm -r /sd-ext/dalvik-cache");
828 }
Koushik Dutta49af23c2010-06-21 13:45:51 -0700829 ensure_root_path_unmounted("DATA:");
Koushik Dutta6c7745d2010-08-07 12:17:13 -0700830 ui_print("Dalvik Cache wiped.\n");
Koushik Duttafd1579b2010-05-01 12:46:55 -0700831 break;
Koushik Duttad63eaef2010-07-14 21:01:21 -0700832 }
Koushik Duttafd1579b2010-05-01 12:46:55 -0700833 case 2:
Koushik Duttad63eaef2010-07-14 21:01:21 -0700834 {
835 if (confirm_selection( "Confirm wipe?", "Yes - Wipe Battery Stats"))
836 wipe_battery_stats();
Koushik Dutta598cfc72010-06-20 09:42:47 -0700837 break;
Koushik Duttad63eaef2010-07-14 21:01:21 -0700838 }
Koushik Dutta598cfc72010-06-20 09:42:47 -0700839 case 3:
Koushik Dutta49af23c2010-06-21 13:45:51 -0700840 handle_failure(1);
841 break;
842 case 4:
Koushik K. Duttaa496b512010-03-19 14:51:45 -0700843 {
844 ui_print("Outputting key codes.\n");
845 ui_print("Go back to end debugging.\n");
846 int key;
847 int action;
848 do
849 {
850 key = ui_wait_key();
851 action = device_handle_key(key, 1);
852 ui_print("Key: %d\n", key);
853 }
854 while (action != GO_BACK);
Koushik Dutta56606a22010-08-23 16:15:33 -0700855 break;
Koushik K. Duttaa496b512010-03-19 14:51:45 -0700856 }
Koushik Duttaf0e31b82010-08-17 16:55:38 -0700857 case 5:
858 {
Koushik Duttaceddcd52010-08-23 16:13:14 -0700859 static char* ext_sizes[] = { "128M",
860 "256M",
861 "512M",
862 "1024M",
863 NULL };
864
865 static char* swap_sizes[] = { "0M",
866 "32M",
867 "64M",
868 "128M",
869 "256M",
870 NULL };
871
872 static char* ext_headers[] = { "Ext Size", "", NULL };
873 static char* swap_headers[] = { "Swap Size", "", NULL };
874
875 int ext_size = get_menu_selection(ext_headers, ext_sizes, 0);
876 if (ext_size == GO_BACK)
877 continue;
878
879 int swap_size = get_menu_selection(swap_headers, swap_sizes, 0);
880 if (swap_size == GO_BACK)
881 continue;
882
883 char sddevice[256];
884 const RootInfo *ri = get_root_info_for_path("SDCARD:");
885 strcpy(sddevice, ri->device);
886 // we only want the mmcblk, not the partition
887 sddevice[strlen("/dev/block/mmcblkX")] = NULL;
888 char cmd[PATH_MAX];
889 setenv("SDPATH", sddevice, 1);
890 sprintf(cmd, "sdparted -es %s -ss %s -efs ext3 -s", ext_sizes[ext_size], swap_sizes[swap_size]);
891 ui_print("Partitioning SD Card... please wait...\n");
892 if (0 == __system(cmd))
893 ui_print("Done!\n");
894 else
895 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 -0700896 break;
Koushik Duttaf0e31b82010-08-17 16:55:38 -0700897 }
Koushik Dutta38e8b2b2010-08-17 22:21:53 -0700898 case 6:
899 {
Koushik Duttaceddcd52010-08-23 16:13:14 -0700900 ensure_root_path_mounted("SYSTEM:");
901 ensure_root_path_mounted("DATA:");
902 ui_print("Fixing permissions...\n");
903 __system("fix_permissions");
904 ui_print("Done!\n");
Koushik Dutta56606a22010-08-23 16:15:33 -0700905 break;
Koushik Dutta38e8b2b2010-08-17 22:21:53 -0700906 }
Koushik K. Duttaa496b512010-03-19 14:51:45 -0700907 }
908 }
Koushik Dutta14239d22010-06-14 15:02:48 -0700909}
910
911void write_fstab_root(char *root_path, FILE *file)
912{
913 RootInfo *info = get_root_info_for_path(root_path);
Koushik Duttaa6522b32010-06-20 13:16:06 -0700914 if (info == NULL) {
915 LOGW("Unable to get root info for %s during fstab generation!", root_path);
Koushik Dutta598cfc72010-06-20 09:42:47 -0700916 return;
Koushik Duttaa6522b32010-06-20 13:16:06 -0700917 }
Koushik Dutta19447c02010-11-10 10:40:44 -0800918 char device[PATH_MAX];
919 int ret = get_root_partition_device(root_path, device);
920 if (ret == 0)
Koushik Dutta14239d22010-06-14 15:02:48 -0700921 {
Koushik Dutta19447c02010-11-10 10:40:44 -0800922 fprintf(file, "%s ", device);
Koushik Dutta14239d22010-06-14 15:02:48 -0700923 }
924 else
925 {
Koushik Dutta19447c02010-11-10 10:40:44 -0800926 fprintf(file, "%s ", info->device);
Koushik Dutta14239d22010-06-14 15:02:48 -0700927 }
928
929 fprintf(file, "%s ", info->mount_point);
Koushik Duttad4060c32010-07-22 20:14:44 -0700930 fprintf(file, "%s %s\n", info->filesystem, info->filesystem_options == NULL ? "rw" : info->filesystem_options);
Koushik Dutta14239d22010-06-14 15:02:48 -0700931}
932
933void create_fstab()
934{
Koushik Duttacd44ab92010-06-23 00:02:14 -0700935 __system("touch /etc/mtab");
Koushik Dutta14239d22010-06-14 15:02:48 -0700936 FILE *file = fopen("/etc/fstab", "w");
Koushik Duttaa6522b32010-06-20 13:16:06 -0700937 if (file == NULL) {
938 LOGW("Unable to create /etc/fstab!");
Koushik Dutta598cfc72010-06-20 09:42:47 -0700939 return;
Koushik Duttaa6522b32010-06-20 13:16:06 -0700940 }
Koushik Dutta14239d22010-06-14 15:02:48 -0700941 write_fstab_root("CACHE:", file);
942 write_fstab_root("DATA:", file);
Koushik Dutta19447c02010-11-10 10:40:44 -0800943#ifdef BOARD_HAS_DATADATA
Koushik Duttaa6522b32010-06-20 13:16:06 -0700944 write_fstab_root("DATADATA:", file);
945#endif
Koushik Dutta14239d22010-06-14 15:02:48 -0700946 write_fstab_root("SYSTEM:", file);
947 write_fstab_root("SDCARD:", file);
948 write_fstab_root("SDEXT:", file);
949 fclose(file);
Koushik Dutta598cfc72010-06-20 09:42:47 -0700950}
951
952void handle_failure(int ret)
953{
954 if (ret == 0)
955 return;
956 if (0 != ensure_root_path_mounted("SDCARD:"))
957 return;
Koushik Duttaa6522b32010-06-20 13:16:06 -0700958 mkdir("/sdcard/clockworkmod", S_IRWXU);
959 __system("cp /tmp/recovery.log /sdcard/clockworkmod/recovery.log");
Koushik Dutta38e8b2b2010-08-17 22:21:53 -0700960 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 -0700961}