Added option to redirect stdout on run_command_always.

There are cases where a command should not write to stdout. For example,
when sending the initial broadcast before the header is printed.

This change adds this option to run_command_always, and uses enums to
make it easier to read what's been passed to it.

BUG: 27953643

Change-Id: I9aed0cb0df4112b31d2079241114e206b9d0bb0c
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 5f9f24b..d9738bb 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -664,7 +664,7 @@
 
     ON_DRY_RUN({ update_progress(timeout_seconds); va_end(ap); return 0; });
 
-    int status = run_command_always(title, false, timeout_seconds, args);
+    int status = run_command_always(title, DONT_DROP_ROOT, NORMAL_STDOUT, timeout_seconds, args);
     va_end(ap);
     return status;
 }
@@ -701,13 +701,15 @@
 
     ON_DRY_RUN({ update_progress(timeout_seconds); va_end(ap); return 0; });
 
-    int status = run_command_always(title, true, timeout_seconds, args);
+    int status = run_command_always(title, DROP_ROOT, NORMAL_STDOUT, timeout_seconds, args);
     va_end(ap);
     return status;
 }
 
 /* forks a command and waits for it to finish */
-int run_command_always(const char *title, bool drop_root, int timeout_seconds, const char *args[]) {
+int run_command_always(const char *title, RootMode root_mode, StdoutMode stdout_mode,
+        int timeout_seconds, const char *args[]) {
+    bool silent = (stdout_mode == REDIRECT_TO_STDERR);
     // TODO: need to check if args is null-terminated, otherwise execvp will crash dumpstate
 
     /* TODO: for now we're simplifying the progress calculation by using the timeout as the weight.
@@ -721,17 +723,25 @@
 
     /* handle error case */
     if (pid < 0) {
-        printf("*** fork: %s\n", strerror(errno));
+        if (!silent) printf("*** fork: %s\n", strerror(errno));
+        MYLOGE("*** fork: %s\n", strerror(errno));
         return pid;
     }
 
     /* handle child case */
     if (pid == 0) {
-        if (drop_root && !drop_root_user()) {
-            printf("*** could not drop root before running %s: %s\n", command, strerror(errno));
+        if (root_mode == DROP_ROOT && !drop_root_user()) {
+        if (!silent) printf("*** fail todrop root before running %s: %s\n", command,
+                strerror(errno));
+            MYLOGE("*** could not drop root before running %s: %s\n", command, strerror(errno));
             return -1;
         }
 
+        if (silent) {
+            // Redirect stderr to stdout
+            dup2(STDERR_FILENO, STDOUT_FILENO);
+        }
+
         /* make sure the child dies when dumpstate dies */
         prctl(PR_SET_PDEATHSIG, SIGKILL);
 
@@ -758,14 +768,14 @@
     if (!ret) {
         if (errno == ETIMEDOUT) {
             format_args(command, args, &cmd);
-            printf("*** command '%s' timed out after %.3fs (killing pid %d)\n", cmd.c_str(),
-                   (float) elapsed / NANOS_PER_SEC, pid);
+            if (!silent) printf("*** command '%s' timed out after %.3fs (killing pid %d)\n",
+            cmd.c_str(), (float) elapsed / NANOS_PER_SEC, pid);
             MYLOGE("command '%s' timed out after %.3fs (killing pid %d)\n", cmd.c_str(),
                    (float) elapsed / NANOS_PER_SEC, pid);
         } else {
             format_args(command, args, &cmd);
-            printf("*** command '%s': Error after %.4fs (killing pid %d)\n", cmd.c_str(),
-                   (float) elapsed / NANOS_PER_SEC, pid);
+            if (!silent) printf("*** command '%s': Error after %.4fs (killing pid %d)\n",
+            cmd.c_str(), (float) elapsed / NANOS_PER_SEC, pid);
             MYLOGE("command '%s': Error after %.4fs (killing pid %d)\n", cmd.c_str(),
                    (float) elapsed / NANOS_PER_SEC, pid);
         }
@@ -773,22 +783,25 @@
         if (!waitpid_with_timeout(pid, 5, NULL)) {
             kill(pid, SIGKILL);
             if (!waitpid_with_timeout(pid, 5, NULL)) {
-                printf("could not kill command '%s' (pid %d) even with SIGKILL.\n", command, pid);
+                if (!silent) printf("could not kill command '%s' (pid %d) even with SIGKILL.\n",
+                        command, pid);
                 MYLOGE("could not kill command '%s' (pid %d) even with SIGKILL.\n", command, pid);
             }
         }
         return -1;
     } else if (status) {
         format_args(command, args, &cmd);
-        printf("*** command '%s' failed: %s\n", cmd.c_str(), strerror(errno));
+        if (!silent) printf("*** command '%s' failed: %s\n", cmd.c_str(), strerror(errno));
         MYLOGE("command '%s' failed: %s\n", cmd.c_str(), strerror(errno));
         return -2;
     }
 
     if (WIFSIGNALED(status)) {
-        printf("*** %s: Killed by signal %d\n", command, WTERMSIG(status));
+        if (!silent) printf("*** %s: Killed by signal %d\n", command, WTERMSIG(status));
+        MYLOGE("*** %s: Killed by signal %d\n", command, WTERMSIG(status));
     } else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) {
-        printf("*** %s: Exit code %d\n", command, WEXITSTATUS(status));
+        if (!silent) printf("*** %s: Exit code %d\n", command, WEXITSTATUS(status));
+        MYLOGE("*** %s: Exit code %d\n", command, WEXITSTATUS(status));
     }
 
     if (weight > 0) {
@@ -859,7 +872,7 @@
     std::string args_string;
     format_args(am_index + 1, am_args, &args_string);
     MYLOGD("send_broadcast command: %s\n", args_string.c_str());
-    run_command_always(NULL, true, 20, am_args);
+    run_command_always(NULL, DROP_ROOT, REDIRECT_TO_STDERR, 20, am_args);
 }
 
 size_t num_props = 0;
@@ -1198,7 +1211,7 @@
 
 void take_screenshot(const std::string& path) {
     const char *args[] = { "/system/bin/screencap", "-p", path.c_str(), NULL };
-    run_command_always(NULL, false, 10, args);
+    run_command_always(NULL, DONT_DROP_ROOT, REDIRECT_TO_STDERR, 10, args);
 }
 
 void vibrate(FILE* vibrator, int ms) {