logd: fix write errors in no_epipe test am: 2e96097ff0 am: dcebdd3bc7

Original change: https://googleplex-android-review.googlesource.com/c/platform/system/logging/+/15523898

Change-Id: Ib3a87399146160c40b8fae7a5bdae12ef06622ce
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index 8793e82..08ab6e2 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -108,11 +108,10 @@
 #endif
 }
 
-#if defined(__GLIBC__) || defined(_WIN32)
+// BSD-based systems like Android/macOS have getprogname(). Others need us to provide one.
+#if !defined(__APPLE__) && !defined(__BIONIC__)
 static const char* getprogname() {
-#if defined(__GLIBC__)
-  return program_invocation_short_name;
-#elif defined(_WIN32)
+#ifdef _WIN32
   static bool first = true;
   static char progname[MAX_PATH] = {};
 
@@ -129,6 +128,8 @@
   }
 
   return progname;
+#else
+  return program_invocation_short_name;
 #endif
 }
 #endif
@@ -267,7 +268,7 @@
             log_message->tag ? log_message->tag : "nullptr", priority_char, timestamp, getpid(),
             tid, log_message->file, log_message->line, log_message->message);
   } else {
-    fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s\n",
+    fprintf(stderr, "%s %c %s %5d %5" PRIu64 "] %s\n",
             log_message->tag ? log_message->tag : "nullptr", priority_char, timestamp, getpid(),
             tid, log_message->message);
   }
diff --git a/liblog/logprint.cpp b/liblog/logprint.cpp
index a5c5edd..639b8d9 100644
--- a/liblog/logprint.cpp
+++ b/liblog/logprint.cpp
@@ -15,10 +15,6 @@
 ** limitations under the License.
 */
 
-#ifndef __MINGW32__
-#define HAVE_STRSEP
-#endif
-
 #include <log/logprint.h>
 
 #include <assert.h>
@@ -38,6 +34,8 @@
 
 #include <cutils/list.h>
 
+#include <algorithm>
+
 #include <log/log.h>
 #include <log/log_read.h>
 #include <private/android_logger.h>
@@ -45,10 +43,6 @@
 #define MS_PER_NSEC 1000000
 #define US_PER_NSEC 1000
 
-#ifndef MIN
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-
 typedef struct FilterInfo_t {
   char* mTag;
   android_LogPriority mPri;
@@ -292,72 +286,71 @@
   return 1;
 }
 
-#ifndef __MINGW32__
-static const char tz[] = "TZ";
-static const char utc[] = "UTC";
+#if !defined(__MINGW32__)
+// Sets $TZ, but allows it to be optionally reset.
+class TzSetter {
+ public:
+  TzSetter(const char* new_tz) {
+    old_tz_ = getenv("TZ");
+    if (old_tz_) old_tz_ = strdup(old_tz_);
+
+    setenv("TZ", new_tz, 1);
+    tzset();
+  }
+
+  ~TzSetter() { free(old_tz_); }
+
+  void Reset() {
+    if (old_tz_) {
+      setenv("TZ", old_tz_, 1);
+    } else {
+      unsetenv("TZ");
+    }
+    tzset();
+  }
+
+ private:
+  char* old_tz_;
+};
 #endif
 
-/**
- * Returns FORMAT_OFF on invalid string
- */
 AndroidLogPrintFormat android_log_formatFromString(const char* formatString) {
-  static AndroidLogPrintFormat format;
-
   /* clang-format off */
-  if (!strcmp(formatString, "brief")) format = FORMAT_BRIEF;
-  else if (!strcmp(formatString, "process")) format = FORMAT_PROCESS;
-  else if (!strcmp(formatString, "tag")) format = FORMAT_TAG;
-  else if (!strcmp(formatString, "thread")) format = FORMAT_THREAD;
-  else if (!strcmp(formatString, "raw")) format = FORMAT_RAW;
-  else if (!strcmp(formatString, "time")) format = FORMAT_TIME;
-  else if (!strcmp(formatString, "threadtime")) format = FORMAT_THREADTIME;
-  else if (!strcmp(formatString, "long")) format = FORMAT_LONG;
-  else if (!strcmp(formatString, "color")) format = FORMAT_MODIFIER_COLOR;
-  else if (!strcmp(formatString, "colour")) format = FORMAT_MODIFIER_COLOR;
-  else if (!strcmp(formatString, "usec")) format = FORMAT_MODIFIER_TIME_USEC;
-  else if (!strcmp(formatString, "nsec")) format = FORMAT_MODIFIER_TIME_NSEC;
-  else if (!strcmp(formatString, "printable")) format = FORMAT_MODIFIER_PRINTABLE;
-  else if (!strcmp(formatString, "year")) format = FORMAT_MODIFIER_YEAR;
-  else if (!strcmp(formatString, "zone")) format = FORMAT_MODIFIER_ZONE;
-  else if (!strcmp(formatString, "epoch")) format = FORMAT_MODIFIER_EPOCH;
-  else if (!strcmp(formatString, "monotonic")) format = FORMAT_MODIFIER_MONOTONIC;
-  else if (!strcmp(formatString, "uid")) format = FORMAT_MODIFIER_UID;
-  else if (!strcmp(formatString, "descriptive")) format = FORMAT_MODIFIER_DESCRIPT;
+  if (!strcmp(formatString, "brief")) return FORMAT_BRIEF;
+  if (!strcmp(formatString, "process")) return FORMAT_PROCESS;
+  if (!strcmp(formatString, "tag")) return FORMAT_TAG;
+  if (!strcmp(formatString, "thread")) return FORMAT_THREAD;
+  if (!strcmp(formatString, "raw")) return FORMAT_RAW;
+  if (!strcmp(formatString, "time")) return FORMAT_TIME;
+  if (!strcmp(formatString, "threadtime")) return FORMAT_THREADTIME;
+  if (!strcmp(formatString, "long")) return FORMAT_LONG;
+  if (!strcmp(formatString, "color")) return FORMAT_MODIFIER_COLOR;
+  if (!strcmp(formatString, "colour")) return FORMAT_MODIFIER_COLOR;
+  if (!strcmp(formatString, "usec")) return FORMAT_MODIFIER_TIME_USEC;
+  if (!strcmp(formatString, "nsec")) return FORMAT_MODIFIER_TIME_NSEC;
+  if (!strcmp(formatString, "printable")) return FORMAT_MODIFIER_PRINTABLE;
+  if (!strcmp(formatString, "year")) return FORMAT_MODIFIER_YEAR;
+  if (!strcmp(formatString, "zone")) return FORMAT_MODIFIER_ZONE;
+  if (!strcmp(formatString, "epoch")) return FORMAT_MODIFIER_EPOCH;
+  if (!strcmp(formatString, "monotonic")) return FORMAT_MODIFIER_MONOTONIC;
+  if (!strcmp(formatString, "uid")) return FORMAT_MODIFIER_UID;
+  if (!strcmp(formatString, "descriptive")) return FORMAT_MODIFIER_DESCRIPT;
     /* clang-format on */
 
-#ifndef __MINGW32__
-  else {
-    extern char* tzname[2];
-    static const char gmt[] = "GMT";
-    char* cp = getenv(tz);
-    if (cp) {
-      cp = strdup(cp);
-    }
-    setenv(tz, formatString, 1);
-    /*
-     * Run tzset here to determine if the timezone is legitimate. If the
-     * zone is GMT, check if that is what was asked for, if not then
-     * did not match any on the system; report an error to caller.
-     */
-    tzset();
-    if (!tzname[0] ||
-        ((!strcmp(tzname[0], utc) || !strcmp(tzname[0], gmt))                  /* error? */
-         && strcasecmp(formatString, utc) && strcasecmp(formatString, gmt))) { /* ok */
-      if (cp) {
-        setenv(tz, cp, 1);
-      } else {
-        unsetenv(tz);
-      }
-      tzset();
-      format = FORMAT_OFF;
-    } else {
-      format = FORMAT_MODIFIER_ZONE;
-    }
-    free(cp);
+#if !defined(__MINGW32__)
+  // Check whether the format string is actually a time zone. If tzname[0]
+  // is the empty string, that's tzset() signalling that it doesn't know
+  // the requested timezone.
+  TzSetter tz(formatString);
+  if (!*tzname[0]) {
+    tz.Reset();
+  } else {
+    // We keep the new time zone as a side effect!
+    return FORMAT_MODIFIER_ZONE;
   }
 #endif
 
-  return format;
+  return FORMAT_OFF;
 }
 
 /**
@@ -433,8 +426,7 @@
   return -1;
 }
 
-#ifndef HAVE_STRSEP
-/* KISS replacement helper for below */
+#if defined(__MINGW32__)  // Windows doesn't have strsep(3).
 static char* strsep(char** stringp, const char* delim) {
   char* token;
   char* ret = *stringp;
@@ -1282,17 +1274,9 @@
           if (!cp) {
             continue;
           }
-          cp = getenv(tz);
-          if (cp) {
-            cp = strdup(cp);
-          }
-          setenv(tz, utc, 1);
-          time.tv_sec = mktime(&tm);
-          if (cp) {
-            setenv(tz, cp, 1);
-            free(cp);
-          } else {
-            unsetenv(tz);
+          {
+            TzSetter tz(cp);
+            time.tv_sec = mktime(&tm);
           }
           list = static_cast<conversionList*>(calloc(1, sizeof(conversionList)));
           list_init(&list->node);
@@ -1503,7 +1487,7 @@
   if (p_format->colored_output) {
     prefixLen =
         snprintf(prefixBuf, sizeof(prefixBuf), "\x1B[%dm", colorFromPri(entry->priority));
-    prefixLen = MIN(prefixLen, sizeof(prefixBuf));
+    prefixLen = std::min(prefixLen, sizeof(prefixBuf));
 
     const char suffixContents[] = "\x1B[0m";
     strcpy(suffixBuf, suffixContents);
@@ -1543,7 +1527,7 @@
     case FORMAT_PROCESS:
       len = snprintf(suffixBuf + suffixLen, sizeof(suffixBuf) - suffixLen, "  (%.*s)\n",
                      (int)entry->tagLen, entry->tag);
-      suffixLen += MIN(len, sizeof(suffixBuf) - suffixLen);
+      suffixLen += std::min(len, sizeof(suffixBuf) - suffixLen);
       len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, "%c(%s%5d) ", priChar,
                      uid, entry->pid);
       break;
diff --git a/liblog/tests/logprint_test.cpp b/liblog/tests/logprint_test.cpp
index 72e53f9..e13934d 100644
--- a/liblog/tests/logprint_test.cpp
+++ b/liblog/tests/logprint_test.cpp
@@ -29,7 +29,7 @@
   auto output_size = convertPrintable(nullptr, input, strlen(input));
   EXPECT_EQ(output_size, strlen(input));
 
-  char output[output_size];
+  char output[output_size + 1];
 
   output_size = convertPrintable(output, input, strlen(input));
   EXPECT_EQ(output_size, strlen(input));
@@ -43,7 +43,7 @@
   auto output_size = convertPrintable(nullptr, input, strlen(input));
   EXPECT_EQ(output_size, strlen(expected_output));
 
-  char output[output_size];
+  char output[output_size + 1];
 
   output_size = convertPrintable(output, input, strlen(input));
   EXPECT_EQ(output_size, strlen(expected_output));
@@ -55,7 +55,7 @@
   auto output_size = convertPrintable(nullptr, input, strlen(input));
   EXPECT_EQ(output_size, strlen(input));
 
-  char output[output_size];
+  char output[output_size + 1];
 
   output_size = convertPrintable(output, input, strlen(input));
   EXPECT_EQ(output_size, strlen(input));
@@ -69,7 +69,7 @@
   auto output_size = convertPrintable(nullptr, input, strlen(input));
   EXPECT_EQ(output_size, strlen(expected_output));
 
-  char output[output_size];
+  char output[output_size + 1];
 
   output_size = convertPrintable(output, input, strlen(input));
   EXPECT_EQ(output_size, strlen(expected_output));
@@ -85,7 +85,7 @@
   auto output_size = convertPrintable(nullptr, input, strlen(input));
   EXPECT_EQ(output_size, strlen(expected_output));
 
-  char output[output_size];
+  char output[output_size + 1];
 
   output_size = convertPrintable(output, input, strlen(input));
   EXPECT_EQ(output_size, strlen(expected_output));
diff --git a/logwrapper/Android.bp b/logwrapper/Android.bp
index 2799947..5b456ac 100644
--- a/logwrapper/Android.bp
+++ b/logwrapper/Android.bp
@@ -28,6 +28,8 @@
 cc_library {
     name: "liblogwrap",
     defaults: ["logwrapper_defaults"],
+    ramdisk_available: true,
+    vendor_ramdisk_available: true,
     recovery_available: true,
     srcs: ["logwrap.cpp"],
     shared_libs: [
diff --git a/rust/tests/config_log_level.rs b/rust/tests/config_log_level.rs
index 7a9a241..c4ff2d1 100644
--- a/rust/tests/config_log_level.rs
+++ b/rust/tests/config_log_level.rs
@@ -9,7 +9,7 @@
         logger::Config::default()
             .with_min_level(log::Level::Trace));
 
-    assert_eq!(init_result, true);
+    assert!(init_result);
     // Setting the level through the Config struct should impact both host and device
     assert_eq!(log::max_level(), log::LevelFilter::Trace);
 
diff --git a/rust/tests/default_init.rs b/rust/tests/default_init.rs
index 413e8c8..837677c 100644
--- a/rust/tests/default_init.rs
+++ b/rust/tests/default_init.rs
@@ -1,6 +1,6 @@
 #[test]
 fn default_init() {
-    assert_eq!(logger::init(Default::default()), true);
+    assert!(logger::init(Default::default()));
 
     if cfg!(target_os = "android") {
         // android_logger has default log level "off"
diff --git a/rust/tests/env_log_level.rs b/rust/tests/env_log_level.rs
index eb86d97..0534be3 100644
--- a/rust/tests/env_log_level.rs
+++ b/rust/tests/env_log_level.rs
@@ -3,7 +3,7 @@
 #[test]
 fn env_log_level() {
     env::set_var("RUST_LOG", "debug");
-    assert_eq!(logger::init(Default::default()), true);
+    assert!(logger::init(Default::default()));
 
     if cfg!(target_os = "android") {
         // android_logger does not read from environment variables
diff --git a/rust/tests/multiple_init.rs b/rust/tests/multiple_init.rs
index 0ac8b2f..7928dcf 100644
--- a/rust/tests/multiple_init.rs
+++ b/rust/tests/multiple_init.rs
@@ -3,6 +3,6 @@
     let first_init = logger::init(Default::default());
     let second_init = logger::init(Default::default());
 
-    assert_eq!(first_init, true);
-    assert_eq!(second_init, false);
+    assert!(first_init);
+    assert!(!second_init);
 }
\ No newline at end of file