syslog.cpp revision b1b60c30bf321c0fc02264b953b5c16c49d34457
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 23static const char* syslog_log_tag = NULL; 24static int syslog_priority_mask = 0xff; 25 26void closelog() { 27 syslog_log_tag = NULL; 28} 29 30void openlog(const char* log_tag, int /*options*/, int /*facility*/) { 31 syslog_log_tag = log_tag; 32} 33 34int 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 43void 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 50void 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