1/* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#define _GNU_SOURCE 17 18#include <hilog_adapter.h> 19 20#include <errno.h> 21#include <stdint.h> 22#include <stdio.h> 23#include <string.h> 24#include <sys/socket.h> 25#include <sys/time.h> 26#include <sys/uio.h> 27#include <sys/un.h> 28#include <time.h> 29#include <unistd.h> 30#include <pthread.h> 31#include <stdlib.h> 32#include <fcntl.h> 33#include <atomic.h> 34 35#include "hilog_common.h" 36#ifdef OHOS_ENABLE_PARAMETER 37#include "sys_param.h" 38#endif 39#include "vsnprintf_s_p.h" 40 41#define LOG_LEN 3 42#define ERROR_FD 2 43#ifdef OHOS_ENABLE_PARAMETER 44#define SYSPARAM_LENGTH 32 45#endif 46 47#define INVALID_SOCKET (-1) 48#define INVALID_RESULT (-1) 49#define CAS_FAIL (-1) 50 51const int SOCKET_TYPE = SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC; 52const struct sockaddr_un SOCKET_ADDR = {AF_UNIX, SOCKET_FILE_DIR INPUT_SOCKET_NAME}; 53 54static bool musl_log_enable = false; 55 56#ifdef OHOS_ENABLE_PARAMETER 57static const char *param_name = "musl.log.enable"; 58static const char *g_logLevelParam = "musl.log.level"; 59#endif 60static int g_logLevel = LOG_ERROR; 61static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER; 62static volatile int g_socketFd = INVALID_SOCKET; 63 64extern int __close(int fd); 65 66// only generate a new socketFd 67static int GenerateHilogSocketFd() 68{ 69 int socketFd = TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCKET_TYPE, 0)); 70 if (socketFd == INVALID_SOCKET) { 71 dprintf(ERROR_FD, "HiLogAdapter_init: Can't create socket! Errno: %d\n", errno); 72 return INVALID_SOCKET; 73 } 74 long int result = 75 TEMP_FAILURE_RETRY(connect(socketFd, (const struct sockaddr *)(&SOCKET_ADDR), sizeof(SOCKET_ADDR))); 76 if (result == INVALID_RESULT) { 77 dprintf(ERROR_FD, "HiLogAdapter_init: Can't connect to server. Errno: %d\n", errno); 78 __close(socketFd); 79 return INVALID_SOCKET; 80 } 81 return socketFd; 82} 83 84HILOG_LOCAL_API 85int CASHilogGlobalSocketFd(int socketFd) 86{ 87 if (socketFd == INVALID_SOCKET) { 88 return INVALID_RESULT; 89 } 90 // we should use CAS to avoid multi-thread problem 91 if (a_cas(&g_socketFd, INVALID_SOCKET, socketFd) != INVALID_SOCKET) { 92 // failure CAS: other threads execute to this branch to close extra fd 93 return CAS_FAIL; 94 } 95 // success CAS: only one thread can execute to this branch 96 return socketFd; 97} 98 99HILOG_LOCAL_API 100bool CheckHilogValid() 101{ 102 int socketFd = INVALID_SOCKET; 103 // read fd by using atomic operation 104#ifdef a_ll 105 socketFd = a_ll(&g_socketFd); 106#else 107 socketFd = g_socketFd; 108#endif 109 return socketFd != INVALID_SOCKET; 110} 111 112/** 113* This interface only for static-link style testcase, this symbol should not be exposed in dynamic libraries 114* Dangerous operation, please do not use in normal business 115*/ 116HILOG_LOCAL_API 117void RefreshHiLogSocketFd() 118{ 119 int socketFd = INVALID_SOCKET; 120 // read fd by using atomic operation 121#ifdef a_ll 122 socketFd = a_ll(&g_socketFd); 123#else 124 socketFd = g_socketFd; 125#endif 126 if (socketFd == INVALID_SOCKET) { 127 return; 128 } 129 a_store(&g_socketFd, INVALID_SOCKET); 130 __close(socketFd); 131} 132 133void InitHilogSocketFd() 134{ 135 int socketFd = GenerateHilogSocketFd(); 136 if (socketFd == INVALID_SOCKET) { 137 return; 138 } 139 int result = CASHilogGlobalSocketFd(socketFd); 140 if (result == CAS_FAIL) { 141 __close(socketFd); 142 } 143} 144 145static int SendMessage(HilogMsg *header, const char *tag, uint16_t tagLen, const char *fmt, uint16_t fmtLen) 146{ 147 bool releaseSocket = false; 148 int socketFd = INVALID_SOCKET; 149 // read fd by using atomic operation 150#ifdef a_ll 151 socketFd = a_ll(&g_socketFd); 152#else 153 socketFd = g_socketFd; 154#endif 155 if (socketFd == INVALID_SOCKET) { 156 socketFd = GenerateHilogSocketFd(); 157 if (socketFd == INVALID_SOCKET) { 158 return INVALID_RESULT; 159 } 160 int result = CASHilogGlobalSocketFd(socketFd); 161 if (result == CAS_FAIL) { 162 releaseSocket = true; 163 } 164 } 165 166 struct timespec ts = {0}; 167 (void)clock_gettime(CLOCK_REALTIME, &ts); 168 struct timespec ts_mono = {0}; 169 (void)clock_gettime(CLOCK_MONOTONIC, &ts_mono); 170 header->tv_sec = (uint32_t)(ts.tv_sec); 171 header->tv_nsec = (uint32_t)(ts.tv_nsec); 172 header->mono_sec = (uint32_t)(ts_mono.tv_sec); 173 header->len = sizeof(HilogMsg) + tagLen + fmtLen; 174 header->tag_len = tagLen; 175 176 struct iovec vec[LOG_LEN] = {0}; 177 vec[0].iov_base = header; // 0 : index of hos log header 178 vec[0].iov_len = sizeof(HilogMsg); // 0 : index of hos log header 179 vec[1].iov_base = (void *)((char *)(tag)); // 1 : index of log tag 180 vec[1].iov_len = tagLen; // 1 : index of log tag 181 vec[2].iov_base = (void *)((char *)(fmt)); // 2 : index of log content 182 vec[2].iov_len = fmtLen; // 2 : index of log content 183 int ret = TEMP_FAILURE_RETRY(writev(socketFd, vec, LOG_LEN)); 184 if (releaseSocket) { 185 __close(socketFd); 186 } 187 return ret; 188} 189 190HILOG_LOCAL_API 191int HiLogAdapterPrintArgs( 192 const LogType type, const LogLevel level, const unsigned int domain, const char *tag, const char *fmt, va_list ap) 193{ 194 char buf[MAX_LOG_LEN] = {0}; 195 196 vsnprintfp_s(buf, MAX_LOG_LEN, MAX_LOG_LEN - 1, true, fmt, ap); 197 198 size_t tagLen = strnlen(tag, MAX_TAG_LEN - 1); 199 size_t logLen = strnlen(buf, MAX_LOG_LEN - 1); 200 HilogMsg header = {0}; 201 header.type = type; 202 header.level = level; 203#ifndef __RECV_MSG_WITH_UCRED_ 204 header.pid = getpid(); 205#endif 206 header.tid = (uint32_t)(gettid()); 207 header.domain = domain; 208 209 return SendMessage(&header, tag, tagLen + 1, buf, logLen + 1); 210} 211 212HILOG_LOCAL_API 213int HiLogAdapterPrint(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, ...) 214{ 215 if (!HiLogAdapterIsLoggable(domain, tag, level)) { 216 return -1; 217 } 218 219 int ret; 220 va_list ap; 221 va_start(ap, fmt); 222 ret = HiLogAdapterPrintArgs(type, level, domain, tag, fmt, ap); 223 va_end(ap); 224 return ret; 225} 226 227HILOG_LOCAL_API 228int HiLogAdapterVaList(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, va_list ap) 229{ 230 if (!HiLogAdapterIsLoggable(domain, tag, level)) { 231 return -1; 232 } 233 return HiLogAdapterPrintArgs(type, level, domain, tag, fmt, ap); 234} 235 236bool is_musl_log_enable() 237{ 238 if (getpid() == 1) { 239 return false; 240 } 241 return musl_log_enable; 242} 243 244bool HiLogAdapterIsLoggable(unsigned int domain, const char *tag, LogLevel level) 245{ 246 if (tag == NULL || level < g_logLevel || level <= LOG_LEVEL_MIN || level >= LOG_LEVEL_MAX) { 247 return false; 248 } 249 250 if (!is_musl_log_enable()) { 251 return false; 252 } 253 254 return true; 255} 256 257#ifdef OHOS_ENABLE_PARAMETER 258bool get_bool_sysparam(CachedHandle cachedhandle) 259{ 260 const char *param_value = CachedParameterGet(cachedhandle); 261 if (param_value != NULL) { 262 if (strcmp(param_value, "true") == 0) { 263 return true; 264 } 265 } 266 return false; 267} 268 269void resetLogLevel() 270{ 271 static CachedHandle muslLogLevelHandle = NULL; 272 if (muslLogLevelHandle == NULL) { 273 muslLogLevelHandle = CachedParameterCreate(g_logLevelParam, "ERROR"); 274 } 275 const char *value = CachedParameterGet(muslLogLevelHandle); 276 if (value != NULL) { 277 if (!strcmp(value, "DEBUG")) { 278 g_logLevel = LOG_DEBUG; 279 } else if (!strcmp(value, "INFO")) { 280 g_logLevel = LOG_INFO; 281 } else if (!strcmp(value, "WARN")) { 282 g_logLevel = LOG_WARN; 283 } else if (!strcmp(value, "ERROR")) { 284 g_logLevel = LOG_ERROR; 285 } else if (!strcmp(value, "FATAL")) { 286 g_logLevel = LOG_FATAL; 287 } else { 288 g_logLevel = LOG_ERROR; 289 } 290 } else { 291 g_logLevel = LOG_ERROR; 292 } 293} 294 295#endif 296 297void musl_log_reset() 298{ 299#if (defined(OHOS_ENABLE_PARAMETER)) 300 static CachedHandle musl_log_Handle = NULL; 301 if (musl_log_Handle == NULL) { 302 musl_log_Handle = CachedParameterCreate(param_name, "false"); 303 } 304 musl_log_enable = get_bool_sysparam(musl_log_Handle); 305 resetLogLevel(); 306#elif (defined(ENABLE_MUSL_LOG)) 307 musl_log_enable = true; 308#endif 309} 310