blob: 23d4094fcdc0ac8c88b98d550f018407a08ecf23 [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. Dutta6060e5c2010-02-11 22:27:06 -080036int signature_check_enabled = 1;
37int script_assert_enabled = 1;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080038static const char *SDCARD_PACKAGE_FILE = "SDCARD:update.zip";
Koushik K. Dutta6060e5c2010-02-11 22:27:06 -080039
40void
41toggle_signature_check()
42{
43 signature_check_enabled = !signature_check_enabled;
44 ui_print("Signature Check: %s\n", signature_check_enabled ? "Enabled" : "Disabled");
45}
46
47void toggle_script_asserts()
48{
49 script_assert_enabled = !script_assert_enabled;
Koushik K. Duttae9234872010-02-12 00:43:24 -080050 ui_print("Script Asserts: %s\n", script_assert_enabled ? "Enabled" : "Disabled");
51}
52
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080053void install_zip(const char* packagefilepath)
Koushik K. Duttae9234872010-02-12 00:43:24 -080054{
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080055 ui_print("\n-- Installing: %s\n", packagefilepath);
56 set_sdcard_update_bootloader_message();
57 int status = install_package(packagefilepath);
Koushik K. Dutta99fb6fe2010-03-03 00:42:58 -080058 ui_reset_progress();
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080059 if (status != INSTALL_SUCCESS) {
60 ui_set_background(BACKGROUND_ICON_ERROR);
61 ui_print("Installation aborted.\n");
Koushik K. Dutta001c5b52010-02-25 14:53:57 -080062 return;
Koushik K. Dutta79ce82c2010-02-25 12:03:17 -080063 }
64 if (firmware_update_pending()) {
65 ui_print("\nReboot via menu to complete\ninstallation.\n");
Koushik K. Dutta001c5b52010-02-25 14:53:57 -080066 }
Koushik K. Dutta001c5b52010-02-25 14:53:57 -080067 ui_set_background(BACKGROUND_ICON_NONE);
Koushik K. Dutta99fb6fe2010-03-03 00:42:58 -080068 ui_print("\nInstall from sdcard complete.\n");
Koushik K. Duttabcdd0032010-02-21 21:10:25 -080069}
70
71char* INSTALL_MENU_ITEMS[] = { "apply sdcard:update.zip",
72 "choose zip from sdcard",
73 "toggle signature verification",
74 "toggle script asserts",
75 NULL };
76#define ITEM_APPLY_SDCARD 0
77#define ITEM_CHOOSE_ZIP 1
78#define ITEM_SIG_CHECK 2
79#define ITEM_ASSERTS 3
80
81void show_install_update_menu()
82{
83 static char* headers[] = { "Apply update from .zip file on SD card",
84 "",
85 NULL
86 };
87 for (;;)
88 {
89 int chosen_item = get_menu_selection(headers, INSTALL_MENU_ITEMS, 0);
90 switch (chosen_item)
91 {
92 case ITEM_ASSERTS:
93 toggle_script_asserts();
94 break;
95 case ITEM_SIG_CHECK:
96 toggle_signature_check();
97 break;
98 case ITEM_APPLY_SDCARD:
99 install_zip(SDCARD_PACKAGE_FILE);
100 break;
101 case ITEM_CHOOSE_ZIP:
102 show_choose_zip_menu();
103 break;
104 default:
105 return;
106 }
107
108 }
109}
110
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800111char** gather_files(const char* directory, const char* fileExtensionOrDirectory, int* numFiles)
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800112{
Koushik K. Duttae9234872010-02-12 00:43:24 -0800113 char path[PATH_MAX] = "";
114 DIR *dir;
115 struct dirent *de;
116 int total = 0;
117 int i;
118 char** files;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800119 int pass;
120 *numFiles = 0;
121 int dirLen = strlen(directory);
Koushik K. Duttae9234872010-02-12 00:43:24 -0800122
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800123 dir = opendir(directory);
124 if (dir == NULL) {
125 ui_print("Couldn't open directory.\n");
126 return NULL;
127 }
128
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800129 int extension_length;
130 if (fileExtensionOrDirectory != NULL)
131 extension_length = strlen(fileExtensionOrDirectory);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800132
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800133 int isCounting = 1;
134 i = 0;
135 for (pass = 0; pass < 2; pass++) {
136 while ((de=readdir(dir)) != NULL) {
137 // skip hidden files
138 if (de->d_name[0] == '.')
139 continue;
140
141 // NULL means that we are gathering directories, so skip this
142 if (fileExtensionOrDirectory != NULL)
143 {
144 // make sure that we can have the desired extension (prevent seg fault)
145 if (strlen(de->d_name) < extension_length)
146 continue;
147 // compare the extension
148 if (strcmp(de->d_name + strlen(de->d_name) - extension_length, fileExtensionOrDirectory) != 0)
149 continue;
150 }
151 else
152 {
153 struct stat info;
154 char* fullFileName = (char*)malloc(strlen(de->d_name) + dirLen + 1);
155 strcpy(fullFileName, directory);
156 strcat(fullFileName, de->d_name);
157 stat(fullFileName, &info);
158 free(fullFileName);
159 // make sure it is a directory
160 if (!(S_ISDIR(info.st_mode)))
161 continue;
162 }
163
164 if (pass == 0)
165 {
166 total++;
167 continue;
168 }
169
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800170 files[i] = (char*) malloc(dirLen + strlen(de->d_name) + 2);
171 strcpy(files[i], directory);
172 strcat(files[i], de->d_name);
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800173 if (fileExtensionOrDirectory == NULL)
174 strcat(files[i], "/");
175 i++;
176 }
177 if (pass == 1)
178 break;
179 if (total == 0)
180 break;
181 rewinddir(dir);
182 *numFiles = total;
183 files = (char**) malloc((total+1)*sizeof(char*));
184 files[total]=NULL;
185 }
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800186
187 if(closedir(dir) < 0) {
188 LOGE("Failed to close directory.");
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800189 }
190
191 if (total==0) {
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800192 return NULL;
193 }
194
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800195 return files;
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800196}
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800197
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800198void free_string_array(char** array)
199{
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800200 char* cursor = array[0];
201 int i = 0;
202 while (cursor != NULL)
203 {
204 free(cursor);
205 cursor = array[++i];
206 }
207 free(array);
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800208}
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800209
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800210// pass in NULL for fileExtensionOrDirectory and you will get a directory chooser
211char* choose_file_menu(const char* directory, const char* fileExtensionOrDirectory, const char* headers[])
212{
213 char path[PATH_MAX] = "";
214 DIR *dir;
215 struct dirent *de;
216 int numFiles = 0;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800217 int numDirs = 0;
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800218 int i;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800219
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800220 int dir_len = strlen(directory);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800221
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800222 char** files = gather_files(directory, fileExtensionOrDirectory, &numFiles);
223 char** dirs;
224 if (fileExtensionOrDirectory != NULL)
225 dirs = gather_files(directory, NULL, &numDirs);
226 int total = numDirs + numFiles;
227 if (total == 0)
228 {
229 ui_print("No files found.\n");
230 return NULL;
231 }
232 char** list = (char**) malloc((total + 1) * sizeof(char*));
233 list[total] = NULL;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800234
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800235
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800236 for (i = 0 ; i < numDirs; i++)
237 {
238 list[i] = strdup(dirs[i] + dir_len);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800239 }
240
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800241 for (i = 0 ; i < numFiles; i++)
242 {
243 list[numDirs + i] = strdup(files[i] + dir_len);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800244 }
245
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800246 for (;;)
247 {
248 int chosen_item = get_menu_selection(headers, list, 0);
249 if (chosen_item == GO_BACK)
250 break;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800251 if (chosen_item < numDirs)
252 {
253 char* subret = choose_file_menu(dirs[chosen_item], fileExtensionOrDirectory, headers);
254 if (subret != NULL)
255 return subret;
256 continue;
257 }
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800258 static char ret[PATH_MAX];
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800259 strcpy(ret, files[chosen_item - numDirs]);
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800260 ui_print("File chosen: %s\n", ret);
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800261 return ret;
262 }
263 return NULL;
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800264}
265
266void show_choose_zip_menu()
267{
Koushik K. Duttae9234872010-02-12 00:43:24 -0800268 if (ensure_root_path_mounted("SDCARD:") != 0) {
269 LOGE ("Can't mount /sdcard\n");
270 return;
271 }
272
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800273 static char* headers[] = { "Choose a zip to apply",
274 "",
275 NULL
276 };
277
278 char* file = choose_file_menu("/sdcard/", ".zip", headers);
279 if (file == NULL)
280 return;
281 char sdcard_package_file[1024];
282 strcpy(sdcard_package_file, "SDCARD:");
283 strcat(sdcard_package_file, file + strlen("/sdcard/"));
284 install_zip(sdcard_package_file);
285}
286
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800287// This was pulled from bionic: The default system command always looks
288// for shell in /system/bin/sh. This is bad.
289#define _PATH_BSHELL "/sbin/sh"
290#define system recovery_system
291extern char **environ;
292int
293system(const char *command)
294{
295 pid_t pid;
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800296 sig_t intsave, quitsave;
297 sigset_t mask, omask;
298 int pstat;
299 char *argp[] = {"sh", "-c", NULL, NULL};
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800300
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800301 if (!command) /* just checking... */
302 return(1);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800303
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800304 argp[2] = (char *)command;
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800305
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800306 sigemptyset(&mask);
307 sigaddset(&mask, SIGCHLD);
308 sigprocmask(SIG_BLOCK, &mask, &omask);
309 switch (pid = vfork()) {
310 case -1: /* error */
311 sigprocmask(SIG_SETMASK, &omask, NULL);
312 return(-1);
313 case 0: /* child */
314 sigprocmask(SIG_SETMASK, &omask, NULL);
315 execve(_PATH_BSHELL, argp, environ);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800316 _exit(127);
317 }
318
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800319 intsave = (sig_t) bsd_signal(SIGINT, SIG_IGN);
320 quitsave = (sig_t) bsd_signal(SIGQUIT, SIG_IGN);
321 pid = waitpid(pid, (int *)&pstat, 0);
322 sigprocmask(SIG_SETMASK, &omask, NULL);
323 (void)bsd_signal(SIGINT, intsave);
324 (void)bsd_signal(SIGQUIT, quitsave);
325 return (pid == -1 ? -1 : pstat);
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800326}
327
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800328void do_nandroid_backup()
329{
330 ui_print("Performing backup...\n");
Koushik K. Dutta001c5b52010-02-25 14:53:57 -0800331 int ret = system("/sbin/nandroid-mobile.sh backup /sdcard/clockworkmod/backup/");
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800332 if (ret != 0)
Koushik K. Dutta225c6b42010-02-21 22:02:24 -0800333 {
Koushik K. Dutta33370db2010-02-25 11:39:07 -0800334 ui_print("Error while backing up! Error code: %d\n", ret);
Koushik K. Dutta225c6b42010-02-21 22:02:24 -0800335 return;
336 }
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800337 ui_print("Backup complete.\n");
338}
339
340void show_nandroid_restore_menu()
341{
342 if (ensure_root_path_mounted("SDCARD:") != 0) {
343 LOGE ("Can't mount /sdcard\n");
Koushik K. Duttae9234872010-02-12 00:43:24 -0800344 return;
345 }
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800346
347 static char* headers[] = { "Choose an image to restore",
348 "",
349 NULL
350 };
Koushik K. Duttae9234872010-02-12 00:43:24 -0800351
Koushik K. Dutta49f56892010-02-25 14:51:05 -0800352 char* file = choose_file_menu("/sdcard/clockworkmod/backup/", NULL, headers);
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800353 if (file == NULL)
354 return;
355 char* command[PATH_MAX];
356 sprintf(command, "nandroid-mobile.sh restore %s", file);
357 ui_print("Performing restore...\n");
Koushik K. Dutta981b0cd2010-02-22 08:53:34 -0800358 int ret = system(command);
Koushik K. Dutta225c6b42010-02-21 22:02:24 -0800359 if (ret != 0)
360 {
361 ui_print("Error while restoring!\n");
362 return;
363 }
Koushik K. Duttabcdd0032010-02-21 21:10:25 -0800364 ui_print("Restore complete.\n");
Koushik K. Dutta03173782010-02-26 14:14:23 -0800365}
366
367void do_mount_usb_storage()
368{
369 system("echo /dev/block/mmcblk0 > /sys/devices/platform/usb_mass_storage/lun0/file");
370 static char* headers[] = { "USB Mass Storage device",
371 "Leaving this menu unmount",
372 "your SD card from your PC.",
373 "",
374 NULL
375 };
376
377 static char* list[] = { "Unmount", NULL };
378
379 for (;;)
380 {
381 int chosen_item = get_menu_selection(headers, list, 0);
382 if (chosen_item == GO_BACK || chosen_item == 0)
383 break;
384 }
385
Koushik K. Duttae81cb752010-02-26 17:44:33 -0800386 system("echo '' > /sys/devices/platform/usb_mass_storage/lun0/file");
Koushik K. Dutta03173782010-02-26 14:14:23 -0800387 system("echo 0 > /sys/devices/platform/usb_mass_storage/lun0/enable");
Koushik K. Duttae81cb752010-02-26 17:44:33 -0800388}
Koushik K. Duttaf68aaaf2010-03-07 13:39:21 -0800389
390int amend_main(int argc, char** argv)
391{
392 if (argc != 2)
393 {
394 printf("Usage: amend <script>\n");
395 return 0;
396 }
397
398 RecoveryCommandContext ctx = { NULL };
399 if (register_update_commands(&ctx)) {
400 LOGE("Can't install update commands\n");
401 }
402
403 struct stat file_info;
404 if (0 != stat(argv[1], &file_info)) {
405 printf("Error executing stat on file: %s\n", argv[1]);
406 return 1;
407 }
408
409 int script_len = file_info.st_size;
410 char* script_data = (char*)malloc(script_len);
411 FILE *file = fopen(argv[1], "rb");
412 fread(script_data, script_len, 1, file);
413 fclose(file);
414
415 /* Parse the script. Note that the script and parse tree are never freed.
416 */
417 const AmCommandList *commands = parseAmendScript(script_data, script_len);
418 if (commands == NULL) {
419 printf("Syntax error in update script\n");
420 return 1;
421 } else {
422 printf("Parsed %.*s\n", script_len, argv[1]);
423 }
424
425 /* Execute the script.
426 */
427 int ret = execCommandList((ExecContext *)1, commands);
428 if (ret != 0) {
429 int num = ret;
430 char *line, *next = script_data;
431 while (next != NULL && ret-- > 0) {
432 line = next;
433 next = memchr(line, '\n', script_data + script_len - line);
434 if (next != NULL) *next++ = '\0';
435 }
436 printf("Failure at line %d:\n%s\n", num, next ? line : "(not found)");
437 return 1;
438 }
439
440 return 0;
441}