Home | History | Annotate | Download | only in bionic
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <errno.h>
     18 #include <stdlib.h>
     19 #include <syslog.h>
     20 
     21 #include "private/libc_logging.h"
     22 
     23 static const char* syslog_log_tag = NULL;
     24 static int syslog_priority_mask = 0xff;
     25 
     26 void closelog() {
     27   syslog_log_tag = NULL;
     28 }
     29 
     30 void openlog(const char* log_tag, int /*options*/, int /*facility*/) {
     31   syslog_log_tag = log_tag;
     32 }
     33 
     34 int setlogmask(int new_mask) {
     35   int old_mask = syslog_priority_mask;
     36   // 0 is used to query the current mask.
     37   if (new_mask != 0) {
     38     syslog_priority_mask = new_mask;
     39   }
     40   return old_mask;
     41 }
     42 
     43 void syslog(int priority, const char* fmt, ...) {
     44   va_list args;
     45   va_start(args, fmt);
     46   vsyslog(priority, fmt, args);
     47   va_end(args);
     48 }
     49 
     50 void vsyslog(int priority, const char* fmt, va_list args) {
     51   int caller_errno = errno;
     52 
     53   // Check whether we're supposed to be logging messages of this priority.
     54   if ((syslog_priority_mask & LOG_MASK(LOG_PRI(priority))) == 0) {
     55     return;
     56   }
     57 
     58   // What's our log tag?
     59   const char* log_tag = syslog_log_tag;
     60   if (log_tag == NULL) {
     61     log_tag = getprogname();
     62   }
     63 
     64   // What's our Android log priority?
     65   priority &= LOG_PRIMASK;
     66   int android_log_priority;
     67   if (priority <= LOG_ERR) {
     68     android_log_priority = ANDROID_LOG_ERROR;
     69   } else if (priority == LOG_WARNING) {
     70     android_log_priority = ANDROID_LOG_WARN;
     71   } else if (priority <= LOG_INFO) {
     72     android_log_priority = ANDROID_LOG_INFO;
     73   } else {
     74     android_log_priority = ANDROID_LOG_DEBUG;
     75   }
     76 
     77   // glibc's printf family support %m directly, but our BSD-based one doesn't.
     78   // If the format string seems to contain "%m", rewrite it.
     79   const char* log_fmt = fmt;
     80   if (strstr(fmt, "%m") != NULL) {
     81     size_t dst_len = 1024;
     82     char* dst = reinterpret_cast<char*>(malloc(dst_len));
     83     log_fmt = dst;
     84 
     85     const char* src = fmt;
     86     for (; dst_len > 0 && *src != '\0'; ++src) {
     87       if (*src == '%' && *(src + 1) == 'm') {
     88         // Expand %m.
     89         size_t n = strlcpy(dst, strerror(caller_errno), dst_len);
     90         if (n >= dst_len) {
     91           n = dst_len;
     92         }
     93         dst += n;
     94         dst_len -= n;
     95         ++src;
     96       } else if (*src == '%' && *(src + 1) == '%') {
     97         // We need to copy pairs of '%'s so the %m test works.
     98         if (dst_len <= 2) {
     99           break;
    100         }
    101         *dst++ = '%'; --dst_len;
    102         *dst++ = '%'; --dst_len;
    103         ++src;
    104       } else {
    105         *dst++ = *src; --dst_len;
    106       }
    107     }
    108     *dst = '\0';
    109   }
    110 
    111   // We can't let __libc_format_log do the formatting because it doesn't support
    112   // all the printf functionality.
    113   char log_line[1024];
    114   vsnprintf(log_line, sizeof(log_line), log_fmt, args);
    115 
    116   if (log_fmt != fmt) {
    117     free(const_cast<char*>(log_fmt));
    118   }
    119 
    120   __libc_format_log(android_log_priority, log_tag, "%s", log_line);
    121 }
    122