Merge "Create a separate copy of the fsck logs" into klp-dev
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index ea60cc8..3500c91 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -53,6 +53,8 @@
 #define E2FSCK_BIN      "/system/bin/e2fsck"
 #define MKSWAP_BIN      "/system/bin/mkswap"
 
+#define FSCK_LOG_FILE   "/dev/fscklogs/log"
+
 #define ZRAM_CONF_DEV   "/sys/block/zram0/disksize"
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
@@ -484,7 +486,8 @@
         INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
 
         ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
-                                      &status, true, LOG_KLOG, true);
+                                      &status, true, LOG_KLOG | LOG_FILE,
+                                      true, FSCK_LOG_FILE);
 
         if (ret < 0) {
             /* No need to check for error in fork, we can't really handle it now */
@@ -801,7 +804,7 @@
         /* Initialize the swap area */
         mkswap_argv[1] = fstab->recs[i].blk_device;
         err = android_fork_execvp_ext(ARRAY_SIZE(mkswap_argv), mkswap_argv,
-                                      &status, true, LOG_KLOG, false);
+                                      &status, true, LOG_KLOG, false, NULL);
         if (err) {
             ERROR("mkswap failed for %s\n", fstab->recs[i].blk_device);
             ret = -1;
diff --git a/logwrapper/include/logwrap/logwrap.h b/logwrapper/include/logwrap/logwrap.h
index 8087f0a..4307a30 100644
--- a/logwrapper/include/logwrap/logwrap.h
+++ b/logwrapper/include/logwrap/logwrap.h
@@ -44,11 +44,15 @@
  *           send a signal twice to signal the caller (once for the child, and
  *           once for the caller)
  *   log_target: Specify where to log the output of the child, either LOG_NONE,
- *           LOG_ALOG (for the Android system log) or LOG_KLOG (for the kernel
- *           log).
+ *           LOG_ALOG (for the Android system log), LOG_KLOG (for the kernel
+ *           log), or LOG_FILE (and you need to specify a pathname in the
+ *           file_path argument, otherwise pass NULL).  These are bit fields,
+ *           and can be OR'ed together to log to multiple places.
  *   abbreviated: If true, capture up to the first 100 lines and last 4K of
  *           output from the child.  The abbreviated output is not dumped to
  *           the specified log until the child has exited.
+ *   file_path: if log_target has the LOG_FILE bit set, then this parameter
+ *           must be set to the pathname of the file to log to.
  *
  * Return value:
  *   0 when logwrap successfully run the child process and captured its status
@@ -58,13 +62,14 @@
  *
  */
 
-/* Values for the log_target parameter android_fork_exec_ext() */
+/* Values for the log_target parameter android_fork_execvp_ext() */
 #define LOG_NONE        0
 #define LOG_ALOG        1
 #define LOG_KLOG        2
+#define LOG_FILE        4
 
 int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
-        int log_target, bool abbreviated);
+        int log_target, bool abbreviated, char *file_path);
 
 /* Similar to above, except abbreviated logging is not available, and if logwrap
  * is true, logging is to the Android system log, and if false, there is no
@@ -74,10 +79,9 @@
                                      bool ignore_int_quit, bool logwrap)
 {
     return android_fork_execvp_ext(argc, argv, status, ignore_int_quit,
-                                   (logwrap ? LOG_ALOG : LOG_NONE), false);
+                                   (logwrap ? LOG_ALOG : LOG_NONE), false, NULL);
 }
 
-
 __END_DECLS
 
 #endif /* __LIBS_LOGWRAP_H */
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 01cc9a1..4ca1db4 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -93,6 +93,7 @@
     char klog_fmt[MAX_KLOG_TAG * 2];
     char *btag;
     bool abbreviated;
+    FILE *fp;
     struct abbr_buf a_buf;
 };
 
@@ -158,11 +159,15 @@
 
 /* Log directly to the specified log */
 static void do_log_line(struct log_info *log_info, char *line) {
-    if (log_info->log_target == LOG_KLOG) {
+    if (log_info->log_target & LOG_KLOG) {
         klog_write(6, log_info->klog_fmt, line);
-    } else if (log_info->log_target == LOG_ALOG) {
+    }
+    if (log_info->log_target & LOG_ALOG) {
         ALOG(LOG_INFO, log_info->btag, "%s", line);
     }
+    if (log_info->log_target & LOG_FILE) {
+        fprintf(log_info->fp, "%s\n", line);
+    }
 }
 
 /* Log to either the abbreviated buf, or directly to the specified log
@@ -290,7 +295,7 @@
 }
 
 static int parent(const char *tag, int parent_read, pid_t pid,
-        int *chld_sts, int log_target, bool abbreviated) {
+        int *chld_sts, int log_target, bool abbreviated, char *file_path) {
     int status = 0;
     char buffer[4096];
     struct pollfd poll_fds[] = {
@@ -300,6 +305,7 @@
         },
     };
     int rc = 0;
+    int fd;
 
     struct log_info log_info;
 
@@ -309,8 +315,6 @@
     bool found_child = false;
     char tmpbuf[256];
 
-    log_info.log_target = log_target;
-    log_info.abbreviated = abbreviated;
     log_info.btag = basename(tag);
     if (!log_info.btag) {
         log_info.btag = (char*) tag;
@@ -323,11 +327,30 @@
         init_abbr_buf(&log_info.a_buf);
     }
 
-    if (log_target == LOG_KLOG) {
+    if (log_target & LOG_KLOG) {
         snprintf(log_info.klog_fmt, sizeof(log_info.klog_fmt),
                  "<6>%.*s: %%s", MAX_KLOG_TAG, log_info.btag);
     }
 
+    if ((log_target & LOG_FILE) && !file_path) {
+        /* No file_path specified, clear the LOG_FILE bit */
+        log_target &= ~LOG_FILE;
+    }
+
+    if (log_target & LOG_FILE) {
+        fd = open(file_path, O_WRONLY | O_CREAT, 0664);
+        if (fd < 0) {
+            ERROR("Cannot log to file %s\n", file_path);
+            log_target &= ~LOG_FILE;
+        } else {
+            lseek(fd, 0, SEEK_END);
+            log_info.fp = fdopen(fd, "a");
+        }
+    }
+
+    log_info.log_target = log_target;
+    log_info.abbreviated = abbreviated;
+
     while (!found_child) {
         if (TEMP_FAILURE_RETRY(poll(poll_fds, ARRAY_SIZE(poll_fds), -1)) < 0) {
             ERROR("poll failed\n");
@@ -432,6 +455,9 @@
 
 err_waitpid:
 err_poll:
+    if (log_target & LOG_FILE) {
+        fclose(log_info.fp); /* Also closes underlying fd */
+    }
     if (abbreviated) {
         free_abbr_buf(&log_info.a_buf);
     }
@@ -451,7 +477,7 @@
 }
 
 int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
-        int log_target, bool abbreviated) {
+        int log_target, bool abbreviated, char *file_path) {
     pid_t pid;
     int parent_ptty;
     int child_ptty;
@@ -523,7 +549,8 @@
             sigaction(SIGQUIT, &ignact, &quitact);
         }
 
-        rc = parent(argv[0], parent_ptty, pid, status, log_target, abbreviated);
+        rc = parent(argv[0], parent_ptty, pid, status, log_target,
+                    abbreviated, file_path);
     }
 
     if (ignore_int_quit) {
diff --git a/logwrapper/logwrapper.c b/logwrapper/logwrapper.c
index d1c6240..d0d8d14 100644
--- a/logwrapper/logwrapper.c
+++ b/logwrapper/logwrapper.c
@@ -80,7 +80,7 @@
     }
 
     rc = android_fork_execvp_ext(argc, &argv[0], &status, true,
-                                 log_target, abbreviated);
+                                 log_target, abbreviated, NULL);
     if (!rc) {
         if (WIFEXITED(status))
             rc = WEXITSTATUS(status);
diff --git a/rootdir/init.rc b/rootdir/init.rc
index cd99574..8150a73 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -133,6 +133,10 @@
 # This is needed by any process that uses socket tagging.
     chmod 0644 /dev/xt_qtaguid
 
+# Create location for fs_mgr to store abbreviated output from filesystem
+# checker programs.
+    mkdir /dev/fscklogs 0770 root system
+
 on post-fs
     # once everything is setup, no need to modify /
     mount rootfs rootfs / ro remount