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 
34 #include "hilog_common.h"
35 #ifdef OHOS_ENABLE_PARAMETER
36 #include "sys_param.h"
37 #endif
38 #include "vsnprintf_s_p.h"
39 
40 #define LOG_LEN 3
41 #define ERROR_FD 2
42 #ifdef OHOS_ENABLE_PARAMETER
43 #define SYSPARAM_LENGTH 32
44 #endif
45 
46 const int SOCKET_TYPE = SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC;
47 const int INVALID_SOCKET = -1;
48 const struct sockaddr_un SOCKET_ADDR = {AF_UNIX, SOCKET_FILE_DIR INPUT_SOCKET_NAME};
49 
50 static bool musl_log_enable = false;
51 
52 #ifdef OHOS_ENABLE_PARAMETER
53 static const char *param_name = "musl.log.enable";
54 static const char *g_logLevelParam = "musl.log.level";
55 #endif
56 static int g_logLevel = LOG_ERROR;
57 static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
58 static volatile int g_socketFd = INVALID_SOCKET;
59 
60 extern int __close(int fd);
61 
Cleanupnull62 static void Cleanup()
63 {
64     if (g_socketFd >= 0) {
65         __close(g_socketFd);
66         g_socketFd = INVALID_SOCKET;
67     }
68 }
69 
GetSocketFdInstancenull70 static int GetSocketFdInstance()
71 {
72     if (g_socketFd == INVALID_SOCKET || fcntl(g_socketFd, F_GETFL) == -1) {
73         pthread_mutex_lock(&g_lock);
74         if (g_socketFd == INVALID_SOCKET || fcntl(g_socketFd, F_GETFL) == -1) {
75             int tempSocketFd = TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCKET_TYPE, 0));
76             if (tempSocketFd < 0) {
77                 dprintf(ERROR_FD, "HiLogAdapter: Can't create socket! Errno: %d\n", errno);
78                 pthread_mutex_unlock(&g_lock);
79                 return tempSocketFd;
80             }
81 
82             long int result =
83                 TEMP_FAILURE_RETRY(connect(tempSocketFd, (const struct sockaddr *)(&SOCKET_ADDR), sizeof(SOCKET_ADDR)));
84             if (result < 0) {
85                 dprintf(ERROR_FD, "HiLogAdapter: Can't connect to server. Errno: %d\n", errno);
86                 if (tempSocketFd >= 0) {
87                     __close(tempSocketFd);
88                 }
89                 pthread_mutex_unlock(&g_lock);
90                 return result;
91             }
92             g_socketFd = tempSocketFd;
93             atexit(Cleanup);
94         }
95         pthread_mutex_unlock(&g_lock);
96     }
97     return g_socketFd;
98 }
99 
SendMessage(HilogMsg *header, const char *tag, uint16_t tagLen, const char *fmt, uint16_t fmtLen)100 static int SendMessage(HilogMsg *header, const char *tag, uint16_t tagLen, const char *fmt, uint16_t fmtLen)
101 {
102     int socketFd = GetSocketFdInstance();
103     if (socketFd < 0) {
104         return socketFd;
105     }
106     struct timespec ts = {0};
107     (void)clock_gettime(CLOCK_REALTIME, &ts);
108     struct timespec ts_mono = {0};
109     (void)clock_gettime(CLOCK_MONOTONIC, &ts_mono);
110     header->tv_sec = (uint32_t)(ts.tv_sec);
111     header->tv_nsec = (uint32_t)(ts.tv_nsec);
112     header->mono_sec = (uint32_t)(ts_mono.tv_sec);
113     header->len = sizeof(HilogMsg) + tagLen + fmtLen;
114     header->tag_len = tagLen;
115 
116     struct iovec vec[LOG_LEN] = {0};
117     vec[0].iov_base = header;                   // 0 : index of hos log header
118     vec[0].iov_len = sizeof(HilogMsg);          // 0 : index of hos log header
119     vec[1].iov_base = (void *)((char *)(tag));  // 1 : index of log tag
120     vec[1].iov_len = tagLen;                    // 1 : index of log tag
121     vec[2].iov_base = (void *)((char *)(fmt));  // 2 : index of log content
122     vec[2].iov_len = fmtLen;                    // 2 : index of log content
123     int ret = TEMP_FAILURE_RETRY(writev(socketFd, vec, LOG_LEN));
124     return ret;
125 }
126 
127 HILOG_LOCAL_API
HiLogAdapterPrintArgs( const LogType type, const LogLevel level, const unsigned int domain, const char *tag, const char *fmt, va_list ap)128 int HiLogAdapterPrintArgs(
129     const LogType type, const LogLevel level, const unsigned int domain, const char *tag, const char *fmt, va_list ap)
130 {
131     char buf[MAX_LOG_LEN] = {0};
132 
133     vsnprintfp_s(buf, MAX_LOG_LEN, MAX_LOG_LEN - 1, true, fmt, ap);
134 
135     size_t tagLen = strnlen(tag, MAX_TAG_LEN - 1);
136     size_t logLen = strnlen(buf, MAX_LOG_LEN - 1);
137     HilogMsg header = {0};
138     header.type = type;
139     header.level = level;
140 #ifndef __RECV_MSG_WITH_UCRED_
141     header.pid = getpid();
142 #endif
143     header.tid = (uint32_t)(gettid());
144     header.domain = domain;
145 
146     return SendMessage(&header, tag, tagLen + 1, buf, logLen + 1);
147 }
148 
149 HILOG_LOCAL_API
HiLogAdapterPrint(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, ...)150 int HiLogAdapterPrint(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, ...)
151 {
152     if (!HiLogAdapterIsLoggable(domain, tag, level)) {
153         return -1;
154     }
155 
156     int ret;
157     va_list ap;
158     va_start(ap, fmt);
159     ret = HiLogAdapterPrintArgs(type, level, domain, tag, fmt, ap);
160     va_end(ap);
161     return ret;
162 }
163 
164 HILOG_LOCAL_API
HiLogAdapterVaList(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, va_list ap)165 int HiLogAdapterVaList(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, va_list ap)
166 {
167     if (!HiLogAdapterIsLoggable(domain, tag, level)) {
168         return -1;
169     }
170     return HiLogAdapterPrintArgs(type, level, domain, tag, fmt, ap);
171 }
172 
is_musl_log_enablenull173 bool is_musl_log_enable()
174 {
175     if (getpid() == 1) {
176         return false;
177     }
178     return musl_log_enable;
179 }
180 
HiLogAdapterIsLoggable(unsigned int domain, const char *tag, LogLevel level)181 bool HiLogAdapterIsLoggable(unsigned int domain, const char *tag, LogLevel level)
182 {
183     if (tag == NULL || level < g_logLevel || level <= LOG_LEVEL_MIN || level >= LOG_LEVEL_MAX) {
184         return false;
185     }
186 
187     if (!is_musl_log_enable()) {
188         return false;
189     }
190 
191     return true;
192 }
193 
194 #ifdef OHOS_ENABLE_PARAMETER
get_bool_sysparam(CachedHandle cachedhandle)195 bool get_bool_sysparam(CachedHandle cachedhandle)
196 {
197     const char *param_value = CachedParameterGet(cachedhandle);
198     if (param_value != NULL) {
199         if (strcmp(param_value, "true") == 0) {
200             return true;
201         }
202     }
203     return false;
204 }
205 
resetLogLevelnull206 void resetLogLevel()
207 {
208     static CachedHandle muslLogLevelHandle = NULL;
209     if (muslLogLevelHandle == NULL) {
210         muslLogLevelHandle = CachedParameterCreate(g_logLevelParam, "ERROR");
211     }
212     const char *value = CachedParameterGet(muslLogLevelHandle);
213     if (value != NULL) {
214         if (!strcmp(value, "DEBUG")) {
215             g_logLevel = LOG_DEBUG;
216         } else if (!strcmp(value, "INFO")) {
217             g_logLevel = LOG_INFO;
218         } else if (!strcmp(value, "WARN")) {
219             g_logLevel = LOG_WARN;
220         } else if (!strcmp(value, "ERROR")) {
221             g_logLevel = LOG_ERROR;
222         } else if (!strcmp(value, "FATAL")) {
223             g_logLevel = LOG_FATAL;
224         } else {
225             g_logLevel = LOG_ERROR;
226         }
227     } else {
228         g_logLevel = LOG_ERROR;
229     }
230 }
231 
232 #endif
233 
musl_log_resetnull234 void musl_log_reset()
235 {
236 #if (defined(OHOS_ENABLE_PARAMETER))
237     static CachedHandle musl_log_Handle = NULL;
238     if (musl_log_Handle == NULL) {
239         musl_log_Handle = CachedParameterCreate(param_name, "false");
240     }
241     musl_log_enable = get_bool_sysparam(musl_log_Handle);
242     resetLogLevel();
243 #elif (defined(ENABLE_MUSL_LOG))
244     musl_log_enable = true;
245 #endif
246 }
247