merge in lmp-mr1-release history after reset to lmp-mr1-dev
diff --git a/recovery.cpp b/recovery.cpp
index e1a2a96..1d22b24 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -25,6 +25,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/klog.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <time.h>
@@ -76,9 +77,14 @@
 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 *LAST_KMSG_FILE = "/cache/recovery/last_kmsg";
+#define KLOG_DEFAULT_LEN (64 * 1024)
 
 #define KEEP_LOG_COUNT 10
 
+// Number of lines per page when displaying a file on screen
+#define LINES_PER_PAGE 30
+
 RecoveryUI* ui = NULL;
 char* locale = NULL;
 char recovery_version[PROPERTY_VALUE_MAX+1];
@@ -259,6 +265,44 @@
     set_bootloader_message(&boot);
 }
 
+// read from kernel log into buffer and write out to file
+static void
+save_kernel_log(const char *destination) {
+    int n;
+    char *buffer;
+    int klog_buf_len;
+    FILE *log;
+
+    klog_buf_len = klogctl(KLOG_SIZE_BUFFER, 0, 0);
+    if (klog_buf_len <= 0) {
+        LOGE("Error getting klog size (%s), using default\n", strerror(errno));
+        klog_buf_len = KLOG_DEFAULT_LEN;
+    }
+
+    buffer = (char *)malloc(klog_buf_len);
+    if (!buffer) {
+        LOGE("Can't alloc %d bytes for klog buffer\n", klog_buf_len);
+        return;
+    }
+
+    n = klogctl(KLOG_READ_ALL, buffer, klog_buf_len);
+    if (n < 0) {
+        LOGE("Error in reading klog (%s)\n", strerror(errno));
+        free(buffer);
+        return;
+    }
+
+    log = fopen_path(destination, "w");
+    if (log == NULL) {
+        LOGE("Can't open %s\n", destination);
+        free(buffer);
+        return;
+    }
+    fwrite(buffer, n, 1, log);
+    check_and_fclose(log, destination);
+    free(buffer);
+}
+
 // How much of the temp log we have copied to the copy in cache.
 static long tmplog_offset = 0;
 
@@ -306,8 +350,11 @@
     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);
+    save_kernel_log(LAST_KMSG_FILE);
     chmod(LOG_FILE, 0600);
     chown(LOG_FILE, 1000, 1000);   // system user
+    chmod(LAST_KMSG_FILE, 0600);
+    chown(LAST_KMSG_FILE, 1000, 1000);   // system user
     chmod(LAST_LOG_FILE, 0640);
     chmod(LAST_INSTALL_FILE, 0644);
     sync();
@@ -681,29 +728,71 @@
     }
     char line[1024];
     int ct = 0;
+    int key = 0;
     redirect_stdio("/dev/null");
     while(fgets(line, sizeof(line), fp) != NULL) {
         ui->Print("%s", line);
         ct++;
-        if (ct % 30 == 0) {
+        if (ct % LINES_PER_PAGE == 0) {
             // give the user time to glance at the entries
-            ui->WaitKey();
+            key = ui->WaitKey();
+
+            if (key == KEY_POWER) {
+                break;
+            }
+
+            if (key == KEY_VOLUMEUP) {
+                // Go back by seeking to the beginning and dumping ct - n
+                // lines.  It's ugly, but this way we don't need to store
+                // the previous offsets.  The files we're dumping here aren't
+                // expected to be very large.
+                int i;
+
+                ct -= 2 * LINES_PER_PAGE;
+                if (ct < 0) {
+                    ct = 0;
+                }
+                fseek(fp, 0, SEEK_SET);
+                for (i = 0; i < ct; i++) {
+                    fgets(line, sizeof(line), fp);
+                }
+                ui->Print("^^^^^^^^^^\n");
+            }
         }
     }
+
+    // If the user didn't abort, then give the user time to glance at
+    // the end of the log, sorry, no rewind here
+    if (key != KEY_POWER) {
+        ui->Print("\n--END-- (press any key)\n");
+        ui->WaitKey();
+    }
+
     redirect_stdio(TEMPORARY_LOG_FILE);
     fclose(fp);
 }
 
 static void choose_recovery_file(Device* device) {
-    int i;
+    unsigned int i;
+    unsigned int n;
     static const char** title_headers = NULL;
     char *filename;
     const char* headers[] = { "Select file to view",
                               "",
                               NULL };
-    char* entries[KEEP_LOG_COUNT + 2];
+    // "Go back" + LAST_KMSG_FILE + KEEP_LOG_COUNT + terminating NULL entry
+    char* entries[KEEP_LOG_COUNT + 3];
     memset(entries, 0, sizeof(entries));
 
+    n = 0;
+    entries[n++] = strdup("Go back");
+
+    // Add kernel kmsg file if available
+    if ((ensure_path_mounted(LAST_KMSG_FILE) == 0) && (access(LAST_KMSG_FILE, R_OK) == 0)) {
+        entries[n++] = strdup(LAST_KMSG_FILE);
+    }
+
+    // Add LAST_LOG_FILE + LAST_LOG_FILE.x
     for (i = 0; i < KEEP_LOG_COUNT; i++) {
         char *filename;
         if (asprintf(&filename, (i==0) ? LAST_LOG_FILE : (LAST_LOG_FILE ".%d"), i) == -1) {
@@ -712,13 +801,12 @@
         }
         if ((ensure_path_mounted(filename) != 0) || (access(filename, R_OK) == -1)) {
             free(filename);
-            entries[i+1] = NULL;
+            entries[n++] = NULL;
             break;
         }
-        entries[i+1] = filename;
+        entries[n++] = filename;
     }
 
-    entries[0] = strdup("Go back");
     title_headers = prepend_title((const char**)headers);
 
     while(1) {
@@ -727,7 +815,7 @@
         file_to_ui(entries[chosen_item]);
     }
 
-    for (i = 0; i < KEEP_LOG_COUNT + 1; i++) {
+    for (i = 0; i < (sizeof(entries) / sizeof(*entries)); i++) {
         free(entries[i]);
     }
 }
diff --git a/uncrypt/uncrypt.c b/uncrypt/uncrypt.c
index 189fa57..361c804 100644
--- a/uncrypt/uncrypt.c
+++ b/uncrypt/uncrypt.c
@@ -164,7 +164,8 @@
     if (f == NULL) {
         return NULL;
     }
-    FILE* fo = fopen(RECOVERY_COMMAND_FILE_TMP, "w");
+    int fd = open(RECOVERY_COMMAND_FILE_TMP, O_WRONLY | O_SYNC);
+    FILE* fo = fdopen(fd, "w");
 
     while (fgets(temp, sizeof(temp), f)) {
         printf("read: %s", temp);
@@ -175,6 +176,7 @@
         fputs(temp, fo);
     }
     fclose(f);
+    fsync(fd);
     fclose(fo);
 
     if (fn) {
@@ -190,7 +192,8 @@
     struct stat sb;
     int ret;
 
-    FILE* mapf = fopen(map_file, "w");
+    int mapfd = open(map_file, O_WRONLY | O_SYNC);
+    FILE* mapf = fdopen(mapfd, "w");
 
     ret = stat(path, &sb);
     if (ret != 0) {
@@ -232,7 +235,7 @@
 
     int wfd = -1;
     if (encrypted) {
-        wfd = open(blk_dev, O_WRONLY);
+        wfd = open(blk_dev, O_WRONLY | O_SYNC);
         if (wfd < 0) {
             ALOGE("failed to open fd for writing: %s\n", strerror(errno));
             return -1;
@@ -302,9 +305,11 @@
         fprintf(mapf, "%d %d\n", ranges[i*2], ranges[i*2+1]);
     }
 
+    fsync(mapfd);
     fclose(mapf);
     close(fd);
     if (encrypted) {
+        fsync(wfd);
         close(wfd);
     }
 
@@ -318,7 +323,7 @@
         struct fstab_rec* v = &fstab->recs[i];
         if (!v->mount_point) continue;
         if (strcmp(v->mount_point, "/misc") == 0) {
-            int fd = open(v->blk_device, O_WRONLY);
+            int fd = open(v->blk_device, O_WRONLY | O_SYNC);
             uint8_t zeroes[1088];   // sizeof(bootloader_message) from recovery
             memset(zeroes, 0, sizeof(zeroes));
 
@@ -333,7 +338,7 @@
                     written += w;
                 }
             }
-
+            fsync(fd);
             close(fd);
         }
     }