1 /*
2 * Copyright (c) 2024-2025 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 #include "hisysevent_easy.h"
17
18 #include <fcntl.h>
19 #include <securec.h>
20 #include <stddef.h>
21 #include <string.h>
22 #include <time.h>
23 #include <unistd.h>
24
25 #include "easy_def.h"
26 #include "easy_event_builder.h"
27 #include "easy_socket_writer.h"
28 #include "easy_util.h"
29
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33
34 static const char CUSTOMIZED_PARAM_KEY[] = "DATA";
35 static const int SEC_2_MILLIS = 1000;
36 static const int MILLS_2_NANOS = 1000000;
37 static const char PROC_SELF_STATUS_PATH[] = "/proc/self/status";
38 static const size_t LINE_BUF_SIZE = 1024;
39 static const char PID_STR_NAME[] = "Pid:";
40 static const int INVALID_PID = 0;
41 static const int ARGS_CNT_ONE = 1;
42
GetTimestamp()43 static int64_t GetTimestamp()
44 {
45 struct timespec tp;
46 clock_gettime(CLOCK_REALTIME, &tp);
47 int64_t time = tp.tv_sec * SEC_2_MILLIS;
48 time += tp.tv_nsec / MILLS_2_NANOS;
49 return time;
50 }
51
ParseTimeZone(long tz)52 static uint8_t ParseTimeZone(long tz)
53 {
54 static long allTimeZones[] = {
55 3600, 7200, 10800, 11880, 14400, 18000, 21600,
56 25200, 28800, 32400, 33480, 36000, 39600, 43200,
57 0, -3600, -7200, -10800, -11880, -14400, 15480,
58 -18000, -19080, -19620, -21600, -22680, -25200, -28800,
59 -30420, -32400, -33480, -36000, -37080, -39600, -43200,
60 -44820, -46800, -50400
61 };
62 uint8_t ret = 14; // 14 is the index of "+0000" in array
63 for (uint8_t index = 0; index < (sizeof(allTimeZones) / sizeof(long)); ++index) {
64 if (allTimeZones[index] == tz) {
65 ret = index;
66 break;
67 }
68 }
69 return ret;
70 }
71
CheckEventType(uint8_t eventType)72 static int CheckEventType(uint8_t eventType)
73 {
74 if ((eventType < EASY_EVENT_TYPE_FAULT) || (eventType > EASY_EVENT_TYPE_BEHAVIOR)) {
75 return ERR_TYPE_INVALID;
76 }
77 return SUCCESS;
78 }
79
ReadPidFromFormatStr(const char * buf,int * pid)80 static void ReadPidFromFormatStr(const char* buf, int* pid)
81 {
82 if (buf == NULL || sscanf_s(buf, "%*[^0-9]%d", pid) != ARGS_CNT_ONE) {
83 *pid = INVALID_PID;
84 }
85 }
86
GetRealPid(void)87 static int GetRealPid(void)
88 {
89 int pid = INVALID_PID;
90 int fd = TEMP_FAILURE_RETRY(open(PROC_SELF_STATUS_PATH, O_RDONLY));
91 if (fd < 0) {
92 return pid;
93 }
94
95 char buf[LINE_BUF_SIZE];
96 (void)memset_s(buf, sizeof(buf), '\0', sizeof(buf));
97 int pos = 0;
98 char curChar = 0;
99 while (1) {
100 ssize_t readCnt = TEMP_FAILURE_RETRY(read(fd, &curChar, sizeof(char)));
101 if (readCnt <= 0 || curChar == '\0') {
102 break;
103 }
104 if (curChar == '\n' || pos == LINE_BUF_SIZE) {
105 if (strncmp(buf, PID_STR_NAME, strlen(PID_STR_NAME)) == 0) {
106 ReadPidFromFormatStr(buf, &pid);
107 break;
108 }
109 pos = 0;
110 (void)memset_s(buf, sizeof(buf), '\0', sizeof(buf));
111 continue;
112 }
113 buf[pos] = curChar;
114 ++pos;
115 }
116 close(fd);
117 return pid;
118 }
119
120 static int gPid = INVALID_PID;
121
InitEventHeader(struct HiSysEventEasyHeader * header,const char * domain,const char * name,const uint8_t eventType)122 static int InitEventHeader(struct HiSysEventEasyHeader* header, const char* domain, const char* name,
123 const uint8_t eventType)
124 {
125 if ((MemoryCopy((uint8_t*)(header->domain), DOMAIN_ARRAY_LEN, (uint8_t*)domain, strlen(domain)) != SUCCESS) ||
126 (MemoryCopy((uint8_t*)(header->name), NAME_ARRAY_LEN, (uint8_t*)name, strlen(name)) != SUCCESS)) {
127 return ERR_MEM_OPT_FAILED;
128 }
129 header->type = eventType - 1; // only 2 bits to store event type
130 header->timestamp = (uint64_t)GetTimestamp();
131 header->timeZone = ParseTimeZone(timezone);
132 if (gPid == INVALID_PID) {
133 gPid = GetRealPid();
134 header->pid = (uint32_t)((gPid != INVALID_PID) ? gPid : getpid());
135 } else {
136 header->pid = gPid;
137 }
138 header->tid = (uint32_t)gettid();
139 header->uid = (uint32_t)getuid();
140 header->isTraceOpened = 0; // no need to allocate memory for trace info.
141 return SUCCESS;
142 }
143
HiSysEventEasyWrite(const char * domain,const char * name,enum HiSysEventEasyType eventType,const char * data)144 int HiSysEventEasyWrite(const char* domain, const char* name, enum HiSysEventEasyType eventType, const char* data)
145 {
146 if ((domain == NULL) || (strlen(domain) > MAX_DOMAIN_LENGTH)) {
147 return ERR_DOMAIN_INVALID;
148 }
149 if ((name == NULL) || (strlen(name) > MAX_EVENT_NAME_LENGTH)) {
150 return ERR_NAME_INVALID;
151 }
152 int ret = CheckEventType(eventType);
153 if (ret != SUCCESS) {
154 return ret;
155 }
156 uint8_t eventBuffer[EVENT_BUFF_LEN] = { 0 };
157 size_t offset = 0;
158 // applend block size
159 *((int32_t*)eventBuffer) = EVENT_BUFF_LEN;
160 offset += sizeof(int32_t);
161 // append header, only two bits to store event type in memory
162 struct HiSysEventEasyHeader header;
163 ret = MemoryInit((uint8_t*)(&header), sizeof(struct HiSysEventEasyHeader));
164 if (ret != SUCCESS) {
165 return ret;
166 }
167 ret = InitEventHeader(&header, domain, name, eventType);
168 if (ret != SUCCESS) {
169 return ret;
170 }
171 ret = AppendHeader(eventBuffer, EVENT_BUFF_LEN, &offset, &header);
172 if (ret != SUCCESS) {
173 return ret;
174 }
175 // append param count, only one cutomized parameter
176 if (offset + sizeof(int32_t) > EVENT_BUFF_LEN) {
177 return ERR_EVENT_BUF_INVALID;
178 }
179 *((int32_t*)(eventBuffer + offset)) = 1;
180 offset += sizeof(int32_t);
181 ret = AppendStringParam(eventBuffer, EVENT_BUFF_LEN, &offset, CUSTOMIZED_PARAM_KEY, data);
182 if (ret != SUCCESS) {
183 return ret;
184 }
185 // write event to socket
186 ret = Write(eventBuffer, EVENT_BUFF_LEN);
187 if (ret != SUCCESS) {
188 return ret;
189 }
190 return SUCCESS;
191 }
192
193 #ifdef __cplusplus
194 }
195 #endif
196