blob: 3f529479fc23b093c64b46c0d2ed89fae56ea6d3 [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);
Koushik K. Dutta99fb6fe2010-03-03 00:42:58 -080055 ui_reset_progress();
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080056 if (status != INSTALL_SUCCESS) {
57 ui_set_background(BACKGROUND_ICON_ERROR);
58 ui_print("Installation aborted.\n");
Koushik K. Dutta001c5b52010-02-25 14:53:57 -080059 return;
Koushik K. Dutta79ce82c2010-02-25 12:03:17 -080060 }
61 if (firmware_update_pending()) {
62 ui_print("\nReboot via menu to complete\ninstallation.\n");
Koushik K. Dutta001c5b52010-02-25 14:53:57 -080063 }
Koushik K. Dutta001c5b52010-02-25 14:53:57 -080064 ui_set_background(BACKGROUND_ICON_NONE);
Koushik K. Dutta99fb6fe2010-03-03 00:42:58 -080065 ui_print("\nInstall from sdcard complete.\n");
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080066}
67
68char* INSTALL_MENU_ITEMS[] = { "apply sdcard:update.zip",
69 "choose zip from sdcard",
70 "toggle signature verification",
71 "toggle script asserts",
72 NULL };
73#define ITEM_APPLY_SDCARD 0
74#define ITEM_CHOOSE_ZIP 1
75#define ITEM_SIG_CHECK 2
76#define ITEM_ASSERTS 3
77
78void show_install_update_menu()
79{
80 static char* headers[] = { "Apply update from .zip file on SD card",
81 "",
82 NULL
83 };
84 for (;;)
85 {
86 int chosen_item = get_menu_selection(headers, INSTALL_MENU_ITEMS, 0);
87 switch (chosen_item)
88 {
89 case ITEM_ASSERTS:
90 toggle_script_asserts();
91 break;
92 case ITEM_SIG_CHECK:
93 toggle_signature_check();
94 break;
95 case ITEM_APPLY_SDCARD:
96 install_zip(SDCARD_PACKAGE_FILE);
97 break;
98 case ITEM_CHOOSE_ZIP:
99 show_choose_zip_menu();
100 break;
101 default:
102 return;
103 }
104
105 }
106}
107
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800108char** gather_files(const char* directory, const char* fileExtensionOrDirectory, int* numFiles)
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800109{
Koushik K. Duttae9234872010-02-12 00:43:24 -0800110 char path[PATH_MAX] = "";
111 DIR *dir;
112 struct dirent *de;
113 int total = 0;
114 int i;
115 char** files;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800116 int pass;
117 *numFiles = 0;
118 int dirLen = strlen(directory);
Koushik K. Duttae9234872010-02-12 00:43:24 -0800119
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800120 dir = opendir(directory);
121 if (dir == NULL) {
122 ui_print("Couldn't open directory.\n");
123 return NULL;
124 }
125
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800126 int extension_length;
127 if (fileExtensionOrDirectory != NULL)
128 extension_length = strlen(fileExtensionOrDirectory);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800129
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800130 int isCounting = 1;
131 i = 0;
132 for (pass = 0; pass < 2; pass++) {
133 while ((de=readdir(dir)) != NULL) {
134 // skip hidden files
135 if (de->d_name[0] == '.')
136 continue;
137
138 // NULL means that we are gathering directories, so skip this
139 if (fileExtensionOrDirectory != NULL)
140 {
141 // make sure that we can have the desired extension (prevent seg fault)
142 if (strlen(de->d_name) < extension_length)
143 continue;
144 // compare the extension
145 if (strcmp(de->d_name + strlen(de->d_name) - extension_length, fileExtensionOrDirectory) != 0)
146 continue;
147 }
148 else
149 {
150 struct stat info;
151 char* fullFileName = (char*)malloc(strlen(de->d_name) + dirLen + 1);
152 strcpy(fullFileName, directory);
153 strcat(fullFileName, de->d_name);
154 stat(fullFileName, &info);
155 free(fullFileName);
156 // make sure it is a directory
157 if (!(S_ISDIR(info.st_mode)))
158 continue;
159 }
160
161 if (pass == 0)
162 {
163 total++;
164 continue;
165 }
166
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800167 files[i] = (char*) malloc(dirLen + strlen(de->d_name) + 2);
168 strcpy(files[i], directory);
169 strcat(files[i], de->d_name);
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800170 if (fileExtensionOrDirectory == NULL)
171 strcat(files[i], "/");
172 i++;
173 }
174 if (pass == 1)
175 break;
176 if (total == 0)
177 break;
178 rewinddir(dir);
179 *numFiles = total;
180 files = (char**) malloc((total+1)*sizeof(char*));
181 files[total]=NULL;
182 }
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800183
184 if(closedir(dir) < 0) {
185 LOGE("Failed to close directory.");
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800186 }
187
188 if (total==0) {
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800189 return NULL;
190 }
191
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800192 return files;
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800193}
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800194
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800195void free_string_array(char** array)
196{
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800197 char* cursor = array[0];
198 int i = 0;
199 while (cursor != NULL)
200 {
201 free(cursor);
202 cursor = array[++i];
203 }
204 free(array);
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800205}
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800206
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800207// pass in NULL for fileExtensionOrDirectory and you will get a directory chooser
208char* choose_file_menu(const char* directory, const char* fileExtensionOrDirectory, const char* headers[])
209{
210 char path[PATH_MAX] = "";
211 DIR *dir;
212 struct dirent *de;
213 int numFiles = 0;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800214 int numDirs = 0;
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800215 int i;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800216
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800217 int dir_len = strlen(directory);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800218
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800219 char** files = gather_files(directory, fileExtensionOrDirectory, &numFiles);
220 char** dirs;
221 if (fileExtensionOrDirectory != NULL)
222 dirs = gather_files(directory, NULL, &numDirs);
223 int total = numDirs + numFiles;
224 if (total == 0)
225 {
226 ui_print("No files found.\n");
227 return NULL;
228 }
229 char** list = (char**) malloc((total + 1) * sizeof(char*));
230 list[total] = NULL;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800231
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800232
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800233 for (i = 0 ; i < numDirs; i++)
234 {
235 list[i] = strdup(dirs[i] + dir_len);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800236 }
237
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800238 for (i = 0 ; i < numFiles; i++)
239 {
240 list[numDirs + i] = strdup(files[i] + dir_len);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800241 }
242
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800243 for (;;)
244 {
245 int chosen_item = get_menu_selection(headers, list, 0);
246 if (chosen_item == GO_BACK)
247 break;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800248 if (chosen_item < numDirs)
249 {
250 char* subret = choose_file_menu(dirs[chosen_item], fileExtensionOrDirectory, headers);
251 if (subret != NULL)
252 return subret;
253 continue;
254 }
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800255 static char ret[PATH_MAX];
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800256 strcpy(ret, files[chosen_item - numDirs]);
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800257 ui_print("File chosen: %s\n", ret);
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800258 return ret;
259 }
260 return NULL;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800261}
262
263void show_choose_zip_menu()
264{
Koushik K. Duttae9234872010-02-12 00:43:24 -0800265 if (ensure_root_path_mounted("SDCARD:") != 0) {
266 LOGE ("Can't mount /sdcard\n");
267 return;
268 }
269
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800270 static char* headers[] = { "Choose a zip to apply",
271 "",
272 NULL
273 };
274
275 char* file = choose_file_menu("/sdcard/", ".zip", headers);
276 if (file == NULL)
277 return;
278 char sdcard_package_file[1024];
279 strcpy(sdcard_package_file, "SDCARD:");
280 strcat(sdcard_package_file, file + strlen("/sdcard/"));
281 install_zip(sdcard_package_file);
282}
283
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800284// This was pulled from bionic: The default system command always looks
285// for shell in /system/bin/sh. This is bad.
286#define _PATH_BSHELL "/sbin/sh"
287#define system recovery_system
288extern char **environ;
289int
290system(const char *command)
291{
292 pid_t pid;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800293 sig_t intsave, quitsave;
294 sigset_t mask, omask;
295 int pstat;
296 char *argp[] = {"sh", "-c", NULL, NULL};
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800297
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800298 if (!command) /* just checking... */
299 return(1);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800300
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800301 argp[2] = (char *)command;
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800302
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800303 sigemptyset(&mask);
304 sigaddset(&mask, SIGCHLD);
305 sigprocmask(SIG_BLOCK, &mask, &omask);
306 switch (pid = vfork()) {
307 case -1: /* error */
308 sigprocmask(SIG_SETMASK, &omask, NULL);
309 return(-1);
310 case 0: /* child */
311 sigprocmask(SIG_SETMASK, &omask, NULL);
312 execve(_PATH_BSHELL, argp, environ);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800313 _exit(127);
314 }
315
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800316 intsave = (sig_t) bsd_signal(SIGINT, SIG_IGN);
317 quitsave = (sig_t) bsd_signal(SIGQUIT, SIG_IGN);
318 pid = waitpid(pid, (int *)&pstat, 0);
319 sigprocmask(SIG_SETMASK, &omask, NULL);
320 (void)bsd_signal(SIGINT, intsave);
321 (void)bsd_signal(SIGQUIT, quitsave);
322 return (pid == -1 ? -1 : pstat);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800323}
324
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800325void do_nandroid_backup()
326{
327 ui_print("Performing backup...\n");
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800328 int ret = system("/sbin/nandroid-mobile.sh backup /sdcard/clockworkmod/backup/");
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800329 if (ret != 0)
Koushik K. Dutta225c6b42010-02-21 22:02:24 -0800330 {
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800331 ui_print("Error while backing up! Error code: %d\n", ret);
Koushik K. Dutta225c6b42010-02-21 22:02:24 -0800332 return;
333 }
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800334 ui_print("Backup complete.\n");
335}
336
337void show_nandroid_restore_menu()
338{
339 if (ensure_root_path_mounted("SDCARD:") != 0) {
340 LOGE ("Can't mount /sdcard\n");
Koushik K. Duttae9234872010-02-12 00:43:24 -0800341 return;
342 }
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800343
344 static char* headers[] = { "Choose an image to restore",
345 "",
346 NULL
347 };
Koushik K. Duttae9234872010-02-12 00:43:24 -0800348
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800349 char* file = choose_file_menu("/sdcard/clockworkmod/backup/", NULL, headers);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800350 if (file == NULL)
351 return;
352 char* command[PATH_MAX];
353 sprintf(command, "nandroid-mobile.sh restore %s", file);
354 ui_print("Performing restore...\n");
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800355 int ret = system(command);
Koushik K. Dutta225c6b42010-02-21 22:02:24 -0800356 if (ret != 0)
357 {
358 ui_print("Error while restoring!\n");
359 return;
360 }
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800361 ui_print("Restore complete.\n");
Koushik K. Dutta03173782010-02-26 14:14:23 -0800362}
363
364void do_mount_usb_storage()
365{
366 system("echo /dev/block/mmcblk0 > /sys/devices/platform/usb_mass_storage/lun0/file");
367 static char* headers[] = { "USB Mass Storage device",
368 "Leaving this menu unmount",
369 "your SD card from your PC.",
370 "",
371 NULL
372 };
373
374 static char* list[] = { "Unmount", NULL };
375
376 for (;;)
377 {
378 int chosen_item = get_menu_selection(headers, list, 0);
379 if (chosen_item == GO_BACK || chosen_item == 0)
380 break;
381 }
382
Koushik K. Duttae81cb752010-02-26 17:44:33 -0800383 system("echo '' > /sys/devices/platform/usb_mass_storage/lun0/file");
Koushik K. Dutta03173782010-02-26 14:14:23 -0800384 system("echo 0 > /sys/devices/platform/usb_mass_storage/lun0/enable");
Koushik K. Duttae81cb752010-02-26 17:44:33 -0800385}