1 /*
2 * Copyright (c) 2021 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 #include "init_group_manager.h"
16
17 #include "init_jobs_internal.h"
18 #include "init_log.h"
19 #include "init_utils.h"
20 #include "securec.h"
21 #include "init_service_manager.h"
22
23 static InitWorkspace g_initWorkspace = {0, 0, {0}, {0}, {0}};
GenerateHashCode(const char * key)24 int GenerateHashCode(const char *key)
25 {
26 int code = 0;
27 for (size_t i = 0; i < strlen(key); i++) {
28 code += key[i] - 'A';
29 }
30 return code;
31 }
32
GetBootGroupMode(void)33 static int GetBootGroupMode(void)
34 {
35 static const char *groupModes[] = {
36 "device.boot.group",
37 "device.charing.group"
38 };
39 for (size_t i = 0; i < ARRAY_LENGTH(groupModes); i++) {
40 if (strcmp(g_initWorkspace.groupModeStr, groupModes[i]) == 0) {
41 return i;
42 }
43 }
44 return (int)GROUP_UNKNOW;
45 }
46
ParseGroupCfgItem(cJSON * root,int type,const char * itemName)47 static int ParseGroupCfgItem(cJSON *root, int type, const char *itemName)
48 {
49 int itemNumber = 0;
50 cJSON *json = GetArrayItem(root, &itemNumber, itemName);
51 if (json == NULL) {
52 return 0;
53 }
54
55 for (int i = 0; i < itemNumber; ++i) {
56 cJSON *item = cJSON_GetArrayItem(json, i);
57 char *strValue = cJSON_GetStringValue(item);
58 if (strValue != NULL) {
59 AddGroupNode(type, strValue);
60 }
61 }
62 return 0;
63 }
64
InitParseGroupCfg_(const char * groupCfg)65 static int InitParseGroupCfg_(const char *groupCfg)
66 {
67 INIT_LOGI("Parse group config %s", groupCfg);
68 char *fileBuf = ReadFileToBuf(groupCfg);
69 INIT_ERROR_CHECK(fileBuf != NULL, return -1, "Failed to read file content %s", groupCfg);
70 cJSON *fileRoot = cJSON_Parse(fileBuf);
71 INIT_ERROR_CHECK(fileRoot != NULL, free(fileBuf);
72 return -1, "Failed to parse json file %s", groupCfg);
73
74 ParseGroupCfgItem(fileRoot, NODE_TYPE_JOBS, "jobs");
75 ParseGroupCfgItem(fileRoot, NODE_TYPE_SERVICES, "services");
76 ParseGroupCfgItem(fileRoot, NODE_TYPE_GROUPS, "groups");
77 cJSON_Delete(fileRoot);
78 free(fileBuf);
79 return 0;
80 }
81
InitImportGroupCfg_(InitGroupNode * groupRoot)82 static int InitImportGroupCfg_(InitGroupNode *groupRoot)
83 {
84 InitGroupNode *groupNode = groupRoot;
85 while (groupNode != NULL) {
86 groupRoot = groupNode->next;
87 InitParseGroupCfg_(groupNode->name);
88 free(groupNode);
89 groupNode = groupRoot;
90 }
91 return 0;
92 }
93
InitFreeGroupNodes_(InitGroupNode * groupRoot)94 static int InitFreeGroupNodes_(InitGroupNode *groupRoot)
95 {
96 InitGroupNode *groupNode = groupRoot;
97 while (groupNode != NULL) {
98 groupRoot = groupNode->next;
99 if (groupNode->type < NODE_TYPE_GROUPS) { // remove from hashmap
100 HashMapRemove(g_initWorkspace.hashMap[groupNode->type], groupNode->name);
101 }
102 free(groupNode);
103 groupNode = groupRoot;
104 }
105 return 0;
106 }
107
GetAbsolutePath(const char * path,const char * cfgName,char * buffer,uint32_t buffSize)108 static char *GetAbsolutePath(const char *path, const char *cfgName, char *buffer, uint32_t buffSize)
109 {
110 int len = 0;
111 size_t cfgNameLen = strlen(cfgName);
112 int ext = 0;
113 if (cfgNameLen > strlen(".cfg")) {
114 ext = strcmp(cfgName + cfgNameLen - strlen(".cfg"), ".cfg") == 0;
115 }
116 if (cfgName[0] != '/') {
117 const char *format = ((ext != 0) ? "%s/%s" : "%s/%s.cfg");
118 len = sprintf_s(buffer, buffSize, format, path, cfgName);
119 } else {
120 const char *format = ((ext != 0) ? "%s" : "%s.cfg");
121 len = sprintf_s(buffer, buffSize, format, cfgName);
122 }
123 if (len <= 0) {
124 return NULL;
125 }
126 buffer[len] = '\0';
127 return buffer;
128 }
129
GroupNodeNodeCompare(const HashNode * node1,const HashNode * node2)130 static int GroupNodeNodeCompare(const HashNode *node1, const HashNode *node2)
131 {
132 InitGroupNode *groupNode1 = HASHMAP_ENTRY(node1, InitGroupNode, hashNode);
133 InitGroupNode *groupNode2 = HASHMAP_ENTRY(node2, InitGroupNode, hashNode);
134 return strcmp(groupNode1->name, groupNode2->name);
135 }
136
GroupNodeKeyCompare(const HashNode * node1,const void * key)137 static int GroupNodeKeyCompare(const HashNode *node1, const void *key)
138 {
139 InitGroupNode *groupNode1 = HASHMAP_ENTRY(node1, InitGroupNode, hashNode);
140 return strcmp(groupNode1->name, (char *)key);
141 }
142
GroupNodeGetKeyHashCode(const void * key)143 static int GroupNodeGetKeyHashCode(const void *key)
144 {
145 return GenerateHashCode((const char *)key);
146 }
147
GroupNodeGetNodeHashCode(const HashNode * node)148 static int GroupNodeGetNodeHashCode(const HashNode *node)
149 {
150 InitGroupNode *groupNode = HASHMAP_ENTRY(node, InitGroupNode, hashNode);
151 return GenerateHashCode((const char *)groupNode->name);
152 }
153
GroupNodeFree(const HashNode * node)154 static void GroupNodeFree(const HashNode *node)
155 {
156 InitGroupNode *groupNode = HASHMAP_ENTRY(node, InitGroupNode, hashNode);
157 free(groupNode);
158 }
159
InitServiceSpace(void)160 void InitServiceSpace(void)
161 {
162 if (g_initWorkspace.initFlags != 0) {
163 return;
164 }
165 HashInfo info = {
166 GroupNodeNodeCompare,
167 GroupNodeKeyCompare,
168 GroupNodeGetNodeHashCode,
169 GroupNodeGetKeyHashCode,
170 GroupNodeFree,
171 GROUP_HASHMAP_BUCKET
172 };
173 for (size_t i = 0; i < ARRAY_LENGTH(g_initWorkspace.hashMap); i++) {
174 int ret = HashMapCreate(&g_initWorkspace.hashMap[i], &info);
175 if (ret != 0) {
176 INIT_LOGE("%s", "Failed to create hash map");
177 }
178 }
179
180 for (int i = 0; i < NODE_TYPE_MAX; i++) {
181 g_initWorkspace.groupNodes[i] = NULL;
182 }
183 // get boot mode
184 char *data = ReadFileData(BOOT_CMD_LINE);
185 if (data != NULL) {
186 int ret = GetProcCmdlineValue(BOOT_GROUP_NAME, data,
187 g_initWorkspace.groupModeStr, sizeof(g_initWorkspace.groupModeStr));
188 if (ret != 0) {
189 INIT_LOGE("%s", "Failed to get boot group");
190 #ifdef INIT_TEST
191 if (GetBootModeFromMisc() == GROUP_CHARING) {
192 strcpy_s(g_initWorkspace.groupModeStr, sizeof(g_initWorkspace.groupModeStr), "device.charing.group");
193 } else {
194 strcpy_s(g_initWorkspace.groupModeStr, sizeof(g_initWorkspace.groupModeStr), BOOT_GROUP_DEFAULT);
195 }
196 #else
197 strcpy_s(g_initWorkspace.groupModeStr, sizeof(g_initWorkspace.groupModeStr), BOOT_GROUP_DEFAULT);
198 #endif
199 }
200 free(data);
201 }
202 INIT_LOGI("boot start %s", g_initWorkspace.groupModeStr);
203 g_initWorkspace.groupMode = GetBootGroupMode();
204 g_initWorkspace.initFlags = 1;
205 }
206
InitParseGroupCfg(void)207 int InitParseGroupCfg(void)
208 {
209 char buffer[128] = {0}; // 128 buffer size
210 char *realPath = GetAbsolutePath(GROUP_DEFAULT_PATH,
211 g_initWorkspace.groupModeStr, buffer, sizeof(buffer));
212 INIT_ERROR_CHECK(realPath != NULL, return -1,
213 "Failed to get path for %s", g_initWorkspace.groupModeStr);
214 InitParseGroupCfg_(realPath);
215 InitGroupNode *groupRoot = g_initWorkspace.groupNodes[NODE_TYPE_GROUPS];
216 int level = 0;
217 while ((groupRoot != NULL) && (level < GROUP_IMPORT_MAX_LEVEL)) { // for more import
218 g_initWorkspace.groupNodes[NODE_TYPE_GROUPS] = NULL;
219 InitImportGroupCfg_(groupRoot);
220 groupRoot = g_initWorkspace.groupNodes[NODE_TYPE_GROUPS];
221 level++;
222 }
223 InitFreeGroupNodes_(g_initWorkspace.groupNodes[NODE_TYPE_GROUPS]);
224 g_initWorkspace.groupNodes[NODE_TYPE_GROUPS] = NULL;
225 return 0;
226 }
227
AddGroupNode(int type,const char * name)228 InitGroupNode *AddGroupNode(int type, const char *name)
229 {
230 INIT_ERROR_CHECK(type <= NODE_TYPE_MAX, return NULL, "Invalid type");
231 INIT_ERROR_CHECK(name != NULL, return NULL, "Invalid name");
232 InitGroupNode *groupNode = GetGroupNode(type, name);
233 if (groupNode != NULL) {
234 return groupNode;
235 }
236 INIT_LOGV("AddGroupNode type %d %p name %s", type, g_initWorkspace.hashMap[type], name);
237 uint32_t nameLen = (uint32_t)strlen(name);
238 groupNode = (InitGroupNode *)calloc(1, sizeof(InitGroupNode) + nameLen + 1);
239 INIT_ERROR_CHECK(groupNode != NULL, return NULL, "Failed to alloc for group %s", name);
240 int ret = memcpy_s(groupNode->name, nameLen + 1, name, nameLen + 1);
241 INIT_ERROR_CHECK(ret == 0, free(groupNode);
242 return NULL, "Failed to alloc for group %s", name);
243 groupNode->type = type;
244 groupNode->next = g_initWorkspace.groupNodes[type];
245 g_initWorkspace.groupNodes[type] = groupNode;
246
247 if (type < NODE_TYPE_GROUPS) { // add hashmap
248 HashMapAdd(g_initWorkspace.hashMap[type], &groupNode->hashNode);
249 }
250 return groupNode;
251 }
252
GetGroupNode(int type,const char * name)253 InitGroupNode *GetGroupNode(int type, const char *name)
254 {
255 if (type >= NODE_TYPE_GROUPS) {
256 return NULL;
257 }
258 INIT_LOGV("GetGroupNode type %d %p name %s", type, g_initWorkspace.hashMap[type], name);
259 HashNode *node = HashMapGet(g_initWorkspace.hashMap[type], name);
260 if (node == NULL) {
261 return NULL;
262 }
263 return HASHMAP_ENTRY(node, InitGroupNode, hashNode);
264 }
265
GetNextGroupNode(int type,const InitGroupNode * curr)266 InitGroupNode *GetNextGroupNode(int type, const InitGroupNode *curr)
267 {
268 INIT_ERROR_CHECK(type <= NODE_TYPE_MAX, return NULL, "Invalid type");
269 if (curr == NULL) {
270 return g_initWorkspace.groupNodes[type];
271 }
272 return curr->next;
273 }
274
DelGroupNode(int type,const char * name)275 void DelGroupNode(int type, const char *name)
276 {
277 if (type >= NODE_TYPE_GROUPS) {
278 return;
279 }
280 INIT_LOGV("DelGroupNode type %d %p name %s", type, g_initWorkspace.hashMap[type], name);
281 HashMapRemove(g_initWorkspace.hashMap[type], name);
282 InitGroupNode *groupNode = g_initWorkspace.groupNodes[type];
283 InitGroupNode *preNode = groupNode;
284 while (groupNode != NULL) {
285 if (strcmp(groupNode->name, name) != 0) {
286 preNode = groupNode;
287 groupNode = groupNode->next;
288 continue;
289 }
290 if (groupNode == g_initWorkspace.groupNodes[type]) {
291 g_initWorkspace.groupNodes[type] = groupNode->next;
292 } else {
293 preNode->next = groupNode->next;
294 }
295 free(groupNode);
296 break;
297 }
298 }
299
CheckNodeValid(int type,const char * name)300 int CheckNodeValid(int type, const char *name)
301 {
302 if (type >= NODE_TYPE_GROUPS) {
303 return -1;
304 }
305 #ifndef INIT_TEST
306 if (g_initWorkspace.groupMode == GROUP_BOOT) {
307 return 0;
308 }
309 HashNode *node = HashMapGet(g_initWorkspace.hashMap[type], name);
310 if (node != NULL) {
311 return 0;
312 }
313 #else
314 HashNode *node = HashMapGet(g_initWorkspace.hashMap[type], name);
315 if (node != NULL) {
316 INIT_LOGI("Found %s in %s group", name, type == NODE_TYPE_JOBS ? "job" : "service");
317 return 0;
318 }
319 if (g_initWorkspace.groupMode == GROUP_BOOT) {
320 return 0;
321 }
322 #endif
323 return -1;
324 }
325
GetGroupHashMap(int type)326 HashMapHandle GetGroupHashMap(int type)
327 {
328 if (type >= NODE_TYPE_GROUPS) {
329 return NULL;
330 }
331 return g_initWorkspace.hashMap[type];
332 }
333
334 #ifdef STARTUP_INIT_TEST
GetInitWorkspace(void)335 InitWorkspace *GetInitWorkspace(void)
336 {
337 return &g_initWorkspace;
338 }
339 #endif