allow recovery packages to wipe cache

updater now has a function "wipe_cache();" which causes recovery to
wipe the cache partition after the successful installation of the
package.  Move log copying around a bit so logs and the last_install
flag file are copied to cache after it's wiped.

Bug: 5314244
Change-Id: Id35a9eb6dcd626c8f3a3a0076074f462ed3d44bd
diff --git a/recovery.c b/recovery.c
index 1e3eb5a..06d6498 100644
--- a/recovery.c
+++ b/recovery.c
@@ -52,9 +52,11 @@
 static const char *INTENT_FILE = "/cache/recovery/intent";
 static const char *LOG_FILE = "/cache/recovery/log";
 static const char *LAST_LOG_FILE = "/cache/recovery/last_log";
+static const char *LAST_INSTALL_FILE = "/cache/recovery/last_install";
 static const char *CACHE_ROOT = "/cache";
 static const char *SDCARD_ROOT = "/sdcard";
 static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
+static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install";
 static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload";
 
 extern UIParameters ui_parameters;    // from ui.c
@@ -223,15 +225,13 @@
 static long tmplog_offset = 0;
 
 static void
-copy_log_file(const char* destination, int append) {
+copy_log_file(const char* source, const char* destination, int append) {
     FILE *log = fopen_path(destination, append ? "a" : "w");
     if (log == NULL) {
         LOGE("Can't open %s\n", destination);
     } else {
-        FILE *tmplog = fopen(TEMPORARY_LOG_FILE, "r");
-        if (tmplog == NULL) {
-            LOGE("Can't open %s\n", TEMPORARY_LOG_FILE);
-        } else {
+        FILE *tmplog = fopen(source, "r");
+        if (tmplog != NULL) {
             if (append) {
                 fseek(tmplog, tmplog_offset, SEEK_SET);  // Since last write
             }
@@ -240,7 +240,7 @@
             if (append) {
                 tmplog_offset = ftell(tmplog);
             }
-            check_and_fclose(tmplog, TEMPORARY_LOG_FILE);
+            check_and_fclose(tmplog, source);
         }
         check_and_fclose(log, destination);
     }
@@ -265,9 +265,13 @@
     }
 
     // Copy logs to cache so the system can find out what happened.
-    copy_log_file(LOG_FILE, true);
-    copy_log_file(LAST_LOG_FILE, false);
+    copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true);
+    copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false);
+    copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false);
+    chmod(LOG_FILE, 0600);
+    chown(LOG_FILE, 1000, 1000);   // system user
     chmod(LAST_LOG_FILE, 0640);
+    chmod(LAST_INSTALL_FILE, 0644);
 
     // Reset to mormal system boot so recovery won't cycle indefinitely.
     struct bootloader_message boot;
@@ -280,6 +284,7 @@
         LOGW("Can't unlink %s\n", COMMAND_FILE);
     }
 
+    ensure_path_unmounted(CACHE_ROOT);
     sync();  // For good measure.
 }
 
@@ -289,6 +294,8 @@
     ui_show_indeterminate_progress();
     ui_print("Formatting %s...\n", volume);
 
+    ensure_path_unmounted(volume);
+
     if (strcmp(volume, "/cache") == 0) {
         // Any part of the log we'd copied to cache is now gone.
         // Reset the pointer so we copy from the beginning of the temp
@@ -469,7 +476,8 @@
 }
 
 static int
-update_directory(const char* path, const char* unmount_when_done) {
+update_directory(const char* path, const char* unmount_when_done,
+                 int* wipe_cache) {
     ensure_path_mounted(path);
 
     const char* MENU_HEADERS[] = { "Choose a package to install:",
@@ -558,7 +566,7 @@
             strlcat(new_path, "/", PATH_MAX);
             strlcat(new_path, item, PATH_MAX);
             new_path[strlen(new_path)-1] = '\0';  // truncate the trailing '/'
-            result = update_directory(new_path, unmount_when_done);
+            result = update_directory(new_path, unmount_when_done, wipe_cache);
             if (result >= 0) break;
         } else {
             // selected a zip file:  attempt to install it, and return
@@ -575,7 +583,7 @@
                 ensure_path_unmounted(unmount_when_done);
             }
             if (copy) {
-                result = install_package(copy);
+                result = install_package(copy, wipe_cache, TEMPORARY_INSTALL_FILE);
                 free(copy);
             } else {
                 result = INSTALL_ERROR;
@@ -650,6 +658,7 @@
         chosen_item = device_perform_action(chosen_item);
 
         int status;
+        int wipe_cache;
         switch (chosen_item) {
             case ITEM_REBOOT:
                 return;
@@ -667,7 +676,15 @@
                 break;
 
             case ITEM_APPLY_SDCARD:
-                status = update_directory(SDCARD_ROOT, SDCARD_ROOT);
+                status = update_directory(SDCARD_ROOT, SDCARD_ROOT, &wipe_cache);
+                if (status == INSTALL_SUCCESS && wipe_cache) {
+                    ui_print("\n-- Wiping cache (at package request)...\n");
+                    if (erase_volume("/cache")) {
+                        ui_print("Cache wipe failed.\n");
+                    } else {
+                        ui_print("Cache wipe complete.\n");
+                    }
+                }
                 if (status >= 0) {
                     if (status != INSTALL_SUCCESS) {
                         ui_set_background(BACKGROUND_ICON_ERROR);
@@ -681,7 +698,15 @@
                 break;
             case ITEM_APPLY_CACHE:
                 // Don't unmount cache at the end of this.
-                status = update_directory(CACHE_ROOT, NULL);
+                status = update_directory(CACHE_ROOT, NULL, &wipe_cache);
+                if (status == INSTALL_SUCCESS && wipe_cache) {
+                    ui_print("\n-- Wiping cache (at package request)...\n");
+                    if (erase_volume("/cache")) {
+                        ui_print("Cache wipe failed.\n");
+                    } else {
+                        ui_print("Cache wipe complete.\n");
+                    }
+                }
                 if (status >= 0) {
                     if (status != INSTALL_SUCCESS) {
                         ui_set_background(BACKGROUND_ICON_ERROR);
@@ -768,7 +793,12 @@
     int status = INSTALL_SUCCESS;
 
     if (update_package != NULL) {
-        status = install_package(update_package);
+        status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE);
+        if (status == INSTALL_SUCCESS && wipe_cache) {
+            if (erase_volume("/cache")) {
+                LOGE("Cache wipe (requested by package) failed.");
+            }
+        }
         if (status != INSTALL_SUCCESS) ui_print("Installation aborted.\n");
     } else if (wipe_data) {
         if (device_wipe_data()) status = INSTALL_ERROR;