Add FORK_EXECVP_OPTION_CAPTURE_OUTPUT to logwrap.h

This allows raw popen calls in e.g. system/netd/ to be replaced
with android_fork_execvp_ext().

Change-Id: I159ece7369fa38ff8782024bef0d7cfafe74ecee
diff --git a/logwrapper/Android.mk b/logwrapper/Android.mk
index 61b4659..ad45b2c 100644
--- a/logwrapper/Android.mk
+++ b/logwrapper/Android.mk
@@ -11,7 +11,7 @@
 LOCAL_SHARED_LIBRARIES := libcutils liblog
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror -std=gnu99
 include $(BUILD_STATIC_LIBRARY)
 
 # ========================================================
@@ -23,7 +23,7 @@
 LOCAL_WHOLE_STATIC_LIBRARIES := liblogwrap
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror -std=gnu99
 include $(BUILD_SHARED_LIBRARY)
 
 # ========================================================
@@ -33,5 +33,5 @@
 LOCAL_SRC_FILES:= logwrapper.c
 LOCAL_MODULE := logwrapper
 LOCAL_STATIC_LIBRARIES := liblog liblogwrap libcutils
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror -std=gnu99
 include $(BUILD_EXECUTABLE)
diff --git a/logwrapper/include/logwrap/logwrap.h b/logwrapper/include/logwrap/logwrap.h
index 449461f..89a8fdd 100644
--- a/logwrapper/include/logwrap/logwrap.h
+++ b/logwrapper/include/logwrap/logwrap.h
@@ -73,7 +73,9 @@
 #define LOG_FILE        4
 
 /* Write data to child's stdin. */
-#define FORK_EXECVP_OPTION_INPUT    0
+#define FORK_EXECVP_OPTION_INPUT             0
+/* Capture data from child's stdout and stderr. */
+#define FORK_EXECVP_OPTION_CAPTURE_OUTPUT    1
 
 struct AndroidForkExecvpOption {
     int opt_type;
@@ -82,6 +84,12 @@
             const uint8_t* input;
             size_t input_len;
         } opt_input;
+        struct {
+            void (*on_output)(const uint8_t* /*output*/,
+                              size_t /*output_len*/,
+                              void* /* user_pointer */);
+            void* user_pointer;
+        } opt_capture_output;
     };
 };
 
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index c7b4835..39bc8fd 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -291,7 +291,8 @@
 }
 
 static int parent(const char *tag, int parent_read, pid_t pid,
-        int *chld_sts, int log_target, bool abbreviated, char *file_path) {
+        int *chld_sts, int log_target, bool abbreviated, char *file_path,
+        const struct AndroidForkExecvpOption* opts, size_t opts_len) {
     int status = 0;
     char buffer[4096];
     struct pollfd poll_fds[] = {
@@ -358,6 +359,13 @@
             sz = TEMP_FAILURE_RETRY(
                 read(parent_read, &buffer[b], sizeof(buffer) - 1 - b));
 
+            for (size_t i = 0; sz > 0 && i < opts_len; ++i) {
+                if (opts[i].opt_type == FORK_EXECVP_OPTION_CAPTURE_OUTPUT) {
+                  opts[i].opt_capture_output.on_output(
+                      (uint8_t*)&buffer[b], sz, opts[i].opt_capture_output.user_pointer);
+                }
+            }
+
             sz += b;
             // Log one line at a time
             for (b = 0; b < sz; b++) {
@@ -484,7 +492,6 @@
     sigset_t blockset;
     sigset_t oldset;
     int rc = 0;
-    size_t i;
 
     rc = pthread_mutex_lock(&fd_mutex);
     if (rc) {
@@ -532,7 +539,7 @@
         close(parent_ptty);
 
         // redirect stdin, stdout and stderr
-        for (i = 0; i < opts_len; ++i) {
+        for (size_t i = 0; i < opts_len; ++i) {
             if (opts[i].opt_type == FORK_EXECVP_OPTION_INPUT) {
                 dup2(child_ptty, 0);
                 break;
@@ -554,7 +561,7 @@
             sigaction(SIGQUIT, &ignact, &quitact);
         }
 
-        for (i = 0; i < opts_len; ++i) {
+        for (size_t 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;
@@ -571,7 +578,7 @@
         }
 
         rc = parent(argv[0], parent_ptty, pid, status, log_target,
-                    abbreviated, file_path);
+                    abbreviated, file_path, opts, opts_len);
     }
 
     if (ignore_int_quit) {