Add the %m GNU extension to printf/wprintf.

And remove the local hack from syslog(3).

Bug: http://b/112776560
Test: ran tests
Change-Id: I5807e729a978df26187ea0ee255bba4ca74220c8
diff --git a/libc/bionic/syslog.cpp b/libc/bionic/syslog.cpp
index d1a0c5b..6b17d26 100644
--- a/libc/bionic/syslog.cpp
+++ b/libc/bionic/syslog.cpp
@@ -49,8 +49,6 @@
 }
 
 void vsyslog(int priority, const char* fmt, va_list args) {
-  int caller_errno = errno;
-
   // Check whether we're supposed to be logging messages of this priority.
   if ((syslog_priority_mask & LOG_MASK(LOG_PRI(priority))) == 0) {
     return;
@@ -75,48 +73,10 @@
     android_log_priority = ANDROID_LOG_DEBUG;
   }
 
-  // glibc's printf family support %m directly, but our BSD-based one doesn't.
-  // If the format string seems to contain "%m", rewrite it.
-  const char* log_fmt = fmt;
-  if (strstr(fmt, "%m") != nullptr) {
-    size_t dst_len = 1024;
-    char* dst = reinterpret_cast<char*>(malloc(dst_len));
-    log_fmt = dst;
-
-    const char* src = fmt;
-    for (; dst_len > 0 && *src != '\0'; ++src) {
-      if (*src == '%' && *(src + 1) == 'm') {
-        // Expand %m.
-        size_t n = strlcpy(dst, strerror(caller_errno), dst_len);
-        if (n >= dst_len) {
-          n = dst_len;
-        }
-        dst += n;
-        dst_len -= n;
-        ++src;
-      } else if (*src == '%' && *(src + 1) == '%') {
-        // We need to copy pairs of '%'s so the %m test works.
-        if (dst_len <= 2) {
-          break;
-        }
-        *dst++ = '%'; --dst_len;
-        *dst++ = '%'; --dst_len;
-        ++src;
-      } else {
-        *dst++ = *src; --dst_len;
-      }
-    }
-    *dst = '\0';
-  }
-
   // We can't let async_safe_format_log do the formatting because it doesn't support
   // all the printf functionality.
   char log_line[1024];
-  vsnprintf(log_line, sizeof(log_line), log_fmt, args);
-
-  if (log_fmt != fmt) {
-    free(const_cast<char*>(log_fmt));
-  }
+  vsnprintf(log_line, sizeof(log_line), fmt, args);
 
   async_safe_format_log(android_log_priority, log_tag, "%s", log_line);
 }
diff --git a/libc/stdio/vfprintf.cpp b/libc/stdio/vfprintf.cpp
index a14963e..8b247e9 100644
--- a/libc/stdio/vfprintf.cpp
+++ b/libc/stdio/vfprintf.cpp
@@ -43,6 +43,7 @@
 #include "printf_common.h"
 
 int FUNCTION_NAME(FILE* fp, const CHAR_TYPE* fmt0, va_list ap) {
+  int caller_errno = errno;
   int n, n2;
   CHAR_TYPE* cp;            /* handy char pointer (short term usage) */
   CHAR_TYPE sign;           /* sign prefix (' ', '+', '-', or \0) */
@@ -451,6 +452,9 @@
         break;
       case 'n':
         __fortify_fatal("%%n not allowed on Android");
+      case 'm':
+        cp = strerror(caller_errno);
+        goto string;
       case 'O':
         flags |= LONGINT;
         __BIONIC_FALLTHROUGH;
@@ -493,6 +497,7 @@
         } else if ((cp = GETARG(char*)) == nullptr) {
           cp = const_cast<char*>("(null)");
         }
+  string:
         if (prec >= 0) {
           size = CHAR_TYPE_STRNLEN(cp, prec);
         } else {
diff --git a/libc/stdio/vfwprintf.cpp b/libc/stdio/vfwprintf.cpp
index 1c3b80d..19cce17 100644
--- a/libc/stdio/vfwprintf.cpp
+++ b/libc/stdio/vfwprintf.cpp
@@ -43,6 +43,7 @@
 #include "printf_common.h"
 
 int FUNCTION_NAME(FILE* fp, const CHAR_TYPE* fmt0, va_list ap) {
+  int caller_errno = errno;
   int n, n2;
   CHAR_TYPE* cp;   /* handy char pointer (short term usage) */
   CHAR_TYPE sign;  /* sign prefix (' ', '+', '-', or \0) */
@@ -436,6 +437,16 @@
         break;
       case 'n':
         __fortify_fatal("%%n not allowed on Android");
+      case 'm':
+        free(convbuf);
+        convbuf = helpers::mbsconv(strerror(caller_errno), prec);
+        if (convbuf == nullptr) {
+            fp->_flags |= __SERR;
+            goto error;
+        } else {
+            cp = convbuf;
+        }
+        goto string;
       case 'O':
         flags |= LONGINT;
         __BIONIC_FALLTHROUGH;
@@ -474,6 +485,7 @@
             cp = convbuf;
           }
         }
+  string:
         if (prec >= 0) {
           size = CHAR_TYPE_STRNLEN(cp, prec);
         } else {