blob: a63163ace7f377a28a48f15728eaaef141768935 [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
33int signature_check_enabled = 1;
34int script_assert_enabled = 1;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080035static const char *SDCARD_PACKAGE_FILE = "SDCARD:update.zip";
Koushik K. Dutta6060e5c2010-02-11 22:27:06 -080036
37void
38toggle_signature_check()
39{
40 signature_check_enabled = !signature_check_enabled;
41 ui_print("Signature Check: %s\n", signature_check_enabled ? "Enabled" : "Disabled");
42}
43
44void toggle_script_asserts()
45{
46 script_assert_enabled = !script_assert_enabled;
Koushik K. Duttae9234872010-02-12 00:43:24 -080047 ui_print("Script Asserts: %s\n", script_assert_enabled ? "Enabled" : "Disabled");
48}
49
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080050void install_zip(const char* packagefilepath)
Koushik K. Duttae9234872010-02-12 00:43:24 -080051{
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080052 ui_print("\n-- Installing: %s\n", packagefilepath);
53 set_sdcard_update_bootloader_message();
54 int status = install_package(packagefilepath);
55 if (status != INSTALL_SUCCESS) {
56 ui_set_background(BACKGROUND_ICON_ERROR);
57 ui_print("Installation aborted.\n");
Koushik K. Dutta001c5b52010-02-25 14:53:57 -080058 return;
Koushik K. Dutta79ce82c2010-02-25 12:03:17 -080059 }
60 if (firmware_update_pending()) {
61 ui_print("\nReboot via menu to complete\ninstallation.\n");
Koushik K. Dutta001c5b52010-02-25 14:53:57 -080062 }
63 ui_print("\nInstall from sdcard complete.\n");
64 ui_set_background(BACKGROUND_ICON_NONE);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080065}
66
67char* INSTALL_MENU_ITEMS[] = { "apply sdcard:update.zip",
68 "choose zip from sdcard",
69 "toggle signature verification",
70 "toggle script asserts",
71 NULL };
72#define ITEM_APPLY_SDCARD 0
73#define ITEM_CHOOSE_ZIP 1
74#define ITEM_SIG_CHECK 2
75#define ITEM_ASSERTS 3
76
77void show_install_update_menu()
78{
79 static char* headers[] = { "Apply update from .zip file on SD card",
80 "",
81 NULL
82 };
83 for (;;)
84 {
85 int chosen_item = get_menu_selection(headers, INSTALL_MENU_ITEMS, 0);
86 switch (chosen_item)
87 {
88 case ITEM_ASSERTS:
89 toggle_script_asserts();
90 break;
91 case ITEM_SIG_CHECK:
92 toggle_signature_check();
93 break;
94 case ITEM_APPLY_SDCARD:
95 install_zip(SDCARD_PACKAGE_FILE);
96 break;
97 case ITEM_CHOOSE_ZIP:
98 show_choose_zip_menu();
99 break;
100 default:
101 return;
102 }
103
104 }
105}
106
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800107char** gather_files(const char* directory, const char* fileExtensionOrDirectory, int* numFiles)
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800108{
Koushik K. Duttae9234872010-02-12 00:43:24 -0800109 char path[PATH_MAX] = "";
110 DIR *dir;
111 struct dirent *de;
112 int total = 0;
113 int i;
114 char** files;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800115 int pass;
116 *numFiles = 0;
117 int dirLen = strlen(directory);
Koushik K. Duttae9234872010-02-12 00:43:24 -0800118
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800119 dir = opendir(directory);
120 if (dir == NULL) {
121 ui_print("Couldn't open directory.\n");
122 return NULL;
123 }
124
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800125 int extension_length;
126 if (fileExtensionOrDirectory != NULL)
127 extension_length = strlen(fileExtensionOrDirectory);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800128
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800129 int isCounting = 1;
130 i = 0;
131 for (pass = 0; pass < 2; pass++) {
132 while ((de=readdir(dir)) != NULL) {
133 // skip hidden files
134 if (de->d_name[0] == '.')
135 continue;
136
137 // NULL means that we are gathering directories, so skip this
138 if (fileExtensionOrDirectory != NULL)
139 {
140 // make sure that we can have the desired extension (prevent seg fault)
141 if (strlen(de->d_name) < extension_length)
142 continue;
143 // compare the extension
144 if (strcmp(de->d_name + strlen(de->d_name) - extension_length, fileExtensionOrDirectory) != 0)
145 continue;
146 }
147 else
148 {
149 struct stat info;
150 char* fullFileName = (char*)malloc(strlen(de->d_name) + dirLen + 1);
151 strcpy(fullFileName, directory);
152 strcat(fullFileName, de->d_name);
153 stat(fullFileName, &info);
154 free(fullFileName);
155 // make sure it is a directory
156 if (!(S_ISDIR(info.st_mode)))
157 continue;
158 }
159
160 if (pass == 0)
161 {
162 total++;
163 continue;
164 }
165
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800166 files[i] = (char*) malloc(dirLen + strlen(de->d_name) + 2);
167 strcpy(files[i], directory);
168 strcat(files[i], de->d_name);
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800169 if (fileExtensionOrDirectory == NULL)
170 strcat(files[i], "/");
171 i++;
172 }
173 if (pass == 1)
174 break;
175 if (total == 0)
176 break;
177 rewinddir(dir);
178 *numFiles = total;
179 files = (char**) malloc((total+1)*sizeof(char*));
180 files[total]=NULL;
181 }
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800182
183 if(closedir(dir) < 0) {
184 LOGE("Failed to close directory.");
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800185 }
186
187 if (total==0) {
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800188 return NULL;
189 }
190
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800191 return files;
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800192}
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800193
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800194void free_string_array(char** array)
195{
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800196 char* cursor = array[0];
197 int i = 0;
198 while (cursor != NULL)
199 {
200 free(cursor);
201 cursor = array[++i];
202 }
203 free(array);
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800204}
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800205
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800206// pass in NULL for fileExtensionOrDirectory and you will get a directory chooser
207char* choose_file_menu(const char* directory, const char* fileExtensionOrDirectory, const char* headers[])
208{
209 char path[PATH_MAX] = "";
210 DIR *dir;
211 struct dirent *de;
212 int numFiles = 0;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800213 int numDirs = 0;
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800214 int i;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800215
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800216 int dir_len = strlen(directory);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800217
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800218 char** files = gather_files(directory, fileExtensionOrDirectory, &numFiles);
219 char** dirs;
220 if (fileExtensionOrDirectory != NULL)
221 dirs = gather_files(directory, NULL, &numDirs);
222 int total = numDirs + numFiles;
223 if (total == 0)
224 {
225 ui_print("No files found.\n");
226 return NULL;
227 }
228 char** list = (char**) malloc((total + 1) * sizeof(char*));
229 list[total] = NULL;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800230
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800231
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800232 for (i = 0 ; i < numDirs; i++)
233 {
234 list[i] = strdup(dirs[i] + dir_len);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800235 }
236
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800237 for (i = 0 ; i < numFiles; i++)
238 {
239 list[numDirs + i] = strdup(files[i] + dir_len);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800240 }
241
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800242 for (;;)
243 {
244 int chosen_item = get_menu_selection(headers, list, 0);
245 if (chosen_item == GO_BACK)
246 break;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800247 if (chosen_item < numDirs)
248 {
249 char* subret = choose_file_menu(dirs[chosen_item], fileExtensionOrDirectory, headers);
250 if (subret != NULL)
251 return subret;
252 continue;
253 }
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800254 static char ret[PATH_MAX];
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800255 strcpy(ret, files[chosen_item - numDirs]);
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800256 ui_print("File chosen: %s\n", ret);
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800257 return ret;
258 }
259 return NULL;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800260}
261
262void show_choose_zip_menu()
263{
Koushik K. Duttae9234872010-02-12 00:43:24 -0800264 if (ensure_root_path_mounted("SDCARD:") != 0) {
265 LOGE ("Can't mount /sdcard\n");
266 return;
267 }
268
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800269 static char* headers[] = { "Choose a zip to apply",
270 "",
271 NULL
272 };
273
274 char* file = choose_file_menu("/sdcard/", ".zip", headers);
275 if (file == NULL)
276 return;
277 char sdcard_package_file[1024];
278 strcpy(sdcard_package_file, "SDCARD:");
279 strcat(sdcard_package_file, file + strlen("/sdcard/"));
280 install_zip(sdcard_package_file);
281}
282
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800283// This was pulled from bionic: The default system command always looks
284// for shell in /system/bin/sh. This is bad.
285#define _PATH_BSHELL "/sbin/sh"
286#define system recovery_system
287extern char **environ;
288int
289system(const char *command)
290{
291 pid_t pid;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800292 sig_t intsave, quitsave;
293 sigset_t mask, omask;
294 int pstat;
295 char *argp[] = {"sh", "-c", NULL, NULL};
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800296
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800297 if (!command) /* just checking... */
298 return(1);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800299
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800300 argp[2] = (char *)command;
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800301
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800302 sigemptyset(&mask);
303 sigaddset(&mask, SIGCHLD);
304 sigprocmask(SIG_BLOCK, &mask, &omask);
305 switch (pid = vfork()) {
306 case -1: /* error */
307 sigprocmask(SIG_SETMASK, &omask, NULL);
308 return(-1);
309 case 0: /* child */
310 sigprocmask(SIG_SETMASK, &omask, NULL);
311 execve(_PATH_BSHELL, argp, environ);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800312 _exit(127);
313 }
314
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800315 intsave = (sig_t) bsd_signal(SIGINT, SIG_IGN);
316 quitsave = (sig_t) bsd_signal(SIGQUIT, SIG_IGN);
317 pid = waitpid(pid, (int *)&pstat, 0);
318 sigprocmask(SIG_SETMASK, &omask, NULL);
319 (void)bsd_signal(SIGINT, intsave);
320 (void)bsd_signal(SIGQUIT, quitsave);
321 return (pid == -1 ? -1 : pstat);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800322}
323
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800324void do_nandroid_backup()
325{
326 ui_print("Performing backup...\n");
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800327 int ret = system("/sbin/nandroid-mobile.sh backup /sdcard/clockworkmod/backup/");
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800328 if (ret != 0)
Koushik K. Dutta225c6b42010-02-21 22:02:24 -0800329 {
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800330 ui_print("Error while backing up! Error code: %d\n", ret);
Koushik K. Dutta225c6b42010-02-21 22:02:24 -0800331 return;
332 }
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800333 ui_print("Backup complete.\n");
334}
335
336void show_nandroid_restore_menu()
337{
338 if (ensure_root_path_mounted("SDCARD:") != 0) {
339 LOGE ("Can't mount /sdcard\n");
Koushik K. Duttae9234872010-02-12 00:43:24 -0800340 return;
341 }
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800342
343 static char* headers[] = { "Choose an image to restore",
344 "",
345 NULL
346 };
Koushik K. Duttae9234872010-02-12 00:43:24 -0800347
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800348 char* file = choose_file_menu("/sdcard/clockworkmod/backup/", NULL, headers);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800349 if (file == NULL)
350 return;
351 char* command[PATH_MAX];
352 sprintf(command, "nandroid-mobile.sh restore %s", file);
353 ui_print("Performing restore...\n");
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800354 int ret = system(command);
Koushik K. Dutta225c6b42010-02-21 22:02:24 -0800355 if (ret != 0)
356 {
357 ui_print("Error while restoring!\n");
358 return;
359 }
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800360 ui_print("Restore complete.\n");
Koushik K. Dutta03173782010-02-26 14:14:23 -0800361}
362
363void do_mount_usb_storage()
364{
365 system("echo /dev/block/mmcblk0 > /sys/devices/platform/usb_mass_storage/lun0/file");
366 static char* headers[] = { "USB Mass Storage device",
367 "Leaving this menu unmount",
368 "your SD card from your PC.",
369 "",
370 NULL
371 };
372
373 static char* list[] = { "Unmount", NULL };
374
375 for (;;)
376 {
377 int chosen_item = get_menu_selection(headers, list, 0);
378 if (chosen_item == GO_BACK || chosen_item == 0)
379 break;
380 }
381
382 system("echo 0 > /sys/devices/platform/usb_mass_storage/lun0/enable");
Koushik K. Dutta6060e5c2010-02-11 22:27:06 -0800383}