am d1b11a04: am e656be33: Merge "Add |opts| argument to android_fork_execvp_ext"

* commit 'd1b11a04903be74ba6a47307d8c3ef2731e3f4ab':
  Add |opts| argument to android_fork_execvp_ext
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 00961c5..c47a585 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -154,8 +154,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 | LOG_FILE,
-                                        true, FSCK_LOG_FILE);
+                                          &status, true, LOG_KLOG | LOG_FILE,
+                                          true, FSCK_LOG_FILE, NULL, 0);
 
             if (ret < 0) {
                 /* No need to check for error in fork, we can't really handle it now */
@@ -172,7 +172,7 @@
 
         ret = android_fork_execvp_ext(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv,
                                       &status, true, LOG_KLOG | LOG_FILE,
-                                      true, FSCK_LOG_FILE);
+                                      true, FSCK_LOG_FILE, NULL, 0);
         if (ret < 0) {
             /* No need to check for error in fork, we can't really handle it now */
             ERROR("Failed trying to run %s\n", F2FS_FSCK_BIN);
@@ -828,7 +828,8 @@
         /* 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, NULL);
+                                      &status, true, LOG_KLOG, false, NULL,
+                                      NULL, 0);
         if (err) {
             ERROR("mkswap failed for %s\n", fstab->recs[i].blk_device);
             ret = -1;
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 470437c..e663501 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -150,13 +150,13 @@
             "/system/bin/fsck.f2fs", "-f", entry->mnt_fsname,
         };
         android_fork_execvp_ext(ARRAY_SIZE(f2fs_argv), (char **)f2fs_argv,
-                                &st, true, LOG_KLOG, true, NULL);
+                                &st, true, LOG_KLOG, true, NULL, NULL, 0);
     } else if (!strcmp(entry->mnt_type, "ext4")) {
         const char *ext4_argv[] = {
             "/system/bin/e2fsck", "-f", "-y", entry->mnt_fsname,
         };
         android_fork_execvp_ext(ARRAY_SIZE(ext4_argv), (char **)ext4_argv,
-                                &st, true, LOG_KLOG, true, NULL);
+                                &st, true, LOG_KLOG, true, NULL, NULL, 0);
     }
 }
 
diff --git a/logwrapper/include/logwrap/logwrap.h b/logwrapper/include/logwrap/logwrap.h
index 4307a30..449461f 100644
--- a/logwrapper/include/logwrap/logwrap.h
+++ b/logwrapper/include/logwrap/logwrap.h
@@ -19,6 +19,7 @@
 #define __LIBS_LOGWRAP_H
 
 #include <stdbool.h>
+#include <stdint.h>
 
 __BEGIN_DECLS
 
@@ -53,6 +54,9 @@
  *           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.
+ *   opts: set to non-NULL if you want to use one or more of the
+ *           FORK_EXECVP_OPTION_* features.
+ *   opts_len: the length of the opts array. When opts is NULL, pass 0.
  *
  * Return value:
  *   0 when logwrap successfully run the child process and captured its status
@@ -68,8 +72,22 @@
 #define LOG_KLOG        2
 #define LOG_FILE        4
 
+/* Write data to child's stdin. */
+#define FORK_EXECVP_OPTION_INPUT    0
+
+struct AndroidForkExecvpOption {
+    int opt_type;
+    union {
+        struct {
+            const uint8_t* input;
+            size_t input_len;
+        } opt_input;
+    };
+};
+
 int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
-        int log_target, bool abbreviated, char *file_path);
+        int log_target, bool abbreviated, char *file_path,
+        const struct AndroidForkExecvpOption* opts, size_t opts_len);
 
 /* 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
@@ -79,7 +97,8 @@
                                      bool ignore_int_quit, bool logwrap)
 {
     return android_fork_execvp_ext(argc, argv, status, ignore_int_quit,
-                                   (logwrap ? LOG_ALOG : LOG_NONE), false, NULL);
+                                   (logwrap ? LOG_ALOG : LOG_NONE), false, NULL,
+                                   NULL, 0);
 }
 
 __END_DECLS
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 44455d1..29aaad4 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -474,7 +474,8 @@
 }
 
 int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
-        int log_target, bool abbreviated, char *file_path) {
+        int log_target, bool abbreviated, char *file_path,
+        const struct AndroidForkExecvpOption* opts, size_t opts_len) {
     pid_t pid;
     int parent_ptty;
     int child_ptty;
@@ -483,6 +484,7 @@
     sigset_t blockset;
     sigset_t oldset;
     int rc = 0;
+    size_t i;
 
     rc = pthread_mutex_lock(&fd_mutex);
     if (rc) {
@@ -529,7 +531,13 @@
         pthread_sigmask(SIG_SETMASK, &oldset, NULL);
         close(parent_ptty);
 
-        // redirect stdout and stderr
+        // redirect stdin, stdout and stderr
+        for (i = 0; i < opts_len; ++i) {
+            if (opts[i].opt_type == FORK_EXECVP_OPTION_INPUT) {
+                dup2(child_ptty, 0);
+                break;
+            }
+        }
         dup2(child_ptty, 1);
         dup2(child_ptty, 2);
         close(child_ptty);
@@ -546,6 +554,22 @@
             sigaction(SIGQUIT, &ignact, &quitact);
         }
 
+        for (i = 0; i < opts_len; ++i) {
+            if (opts[i].opt_type == FORK_EXECVP_OPTION_INPUT) {
+                size_t left = opts[i].opt_input.input_len;
+                const uint8_t* input = opts[i].opt_input.input;
+                while (left > 0) {
+                    ssize_t res =
+                        TEMP_FAILURE_RETRY(write(parent_ptty, input, left));
+                    if (res < 0) {
+                        break;
+                    }
+                    left -= res;
+                    input += res;
+                }
+            }
+        }
+
         rc = parent(argv[0], parent_ptty, pid, status, log_target,
                     abbreviated, file_path);
     }
diff --git a/logwrapper/logwrapper.c b/logwrapper/logwrapper.c
index 9e0385d..55b71c7 100644
--- a/logwrapper/logwrapper.c
+++ b/logwrapper/logwrapper.c
@@ -81,7 +81,7 @@
     }
 
     rc = android_fork_execvp_ext(argc, &argv[0], &status, true,
-                                 log_target, abbreviated, NULL);
+                                 log_target, abbreviated, NULL, NULL, 0);
     if (!rc) {
         if (WIFEXITED(status))
             rc = WEXITSTATUS(status);