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
16 #include "param_service.h"
17
18 #include <ctype.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <sys/ipc.h>
24 #include <sys/msg.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29
30 #include "init_param.h"
31 #include "init_utils.h"
32 #include "loop_event.h"
33 #include "param_message.h"
34 #include "param_manager.h"
35 #include "param_request.h"
36 #include "trigger_manager.h"
37
38 static ParamWorkSpace g_paramWorkSpace = { 0, {}, NULL, {}, NULL, NULL };
39
OnClose(ParamTaskPtr client)40 static void OnClose(ParamTaskPtr client)
41 {
42 PARAM_LOGV("OnClose %p", client);
43 ParamWatcher *watcher = (ParamWatcher *)ParamGetTaskUserData(client);
44 if (client == g_paramWorkSpace.watcherTask) {
45 ClearWatchTrigger(watcher, TRIGGER_PARAM_WATCH);
46 g_paramWorkSpace.watcherTask = NULL;
47 } else {
48 ClearWatchTrigger(watcher, TRIGGER_PARAM_WAIT);
49 }
50 }
51
TimerCallback(const ParamTaskPtr timer,void * context)52 static void TimerCallback(const ParamTaskPtr timer, void *context)
53 {
54 UNUSED(context);
55 UNUSED(timer);
56 int ret = CheckWatchTriggerTimeout();
57 // no wait node
58 if (ret == 0 && g_paramWorkSpace.timer != NULL) {
59 ParamTaskClose(g_paramWorkSpace.timer);
60 g_paramWorkSpace.timer = NULL;
61 }
62 }
63
AddParam(WorkSpace * workSpace,const char * name,const char * value,uint32_t * dataIndex)64 static int AddParam(WorkSpace *workSpace, const char *name, const char *value, uint32_t *dataIndex)
65 {
66 ParamTrieNode *node = AddTrieNode(workSpace, name, strlen(name));
67 PARAM_CHECK(node != NULL, return PARAM_CODE_REACHED_MAX, "Failed to add node");
68 ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, node->dataIndex);
69 if (entry == NULL) {
70 uint32_t offset = AddParamNode(workSpace, name, strlen(name), value, strlen(value));
71 PARAM_CHECK(offset > 0, return PARAM_CODE_REACHED_MAX, "Failed to allocate name %s", name);
72 SaveIndex(&node->dataIndex, offset);
73 }
74 if (dataIndex != NULL) {
75 *dataIndex = node->dataIndex;
76 }
77 return 0;
78 }
79
UpdateParam(const WorkSpace * workSpace,uint32_t * dataIndex,const char * name,const char * value)80 static int UpdateParam(const WorkSpace *workSpace, uint32_t *dataIndex, const char *name, const char *value)
81 {
82 ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, *dataIndex);
83 PARAM_CHECK(entry != NULL, return PARAM_CODE_REACHED_MAX, "Failed to update param value %s %u", name, *dataIndex);
84 PARAM_CHECK(entry->keyLength == strlen(name), return PARAM_CODE_INVALID_NAME, "Failed to check name len %s", name);
85
86 uint32_t valueLen = strlen(value);
87 uint32_t commitId = atomic_load_explicit(&entry->commitId, memory_order_relaxed);
88 atomic_store_explicit(&entry->commitId, commitId | PARAM_FLAGS_MODIFY, memory_order_relaxed);
89
90 if (entry->valueLength < PARAM_VALUE_LEN_MAX && valueLen < PARAM_VALUE_LEN_MAX) {
91 int ret = memcpy_s(entry->data + entry->keyLength + 1, PARAM_VALUE_LEN_MAX, value, valueLen + 1);
92 PARAM_CHECK(ret == EOK, return PARAM_CODE_INVALID_VALUE, "Failed to copy value");
93 entry->valueLength = valueLen;
94 }
95 uint32_t flags = commitId & ~PARAM_FLAGS_COMMITID;
96 atomic_store_explicit(&entry->commitId, (++commitId) | flags, memory_order_release);
97 futex_wake(&entry->commitId, INT_MAX);
98 return 0;
99 }
100
CheckParamValue(const WorkSpace * workSpace,const ParamTrieNode * node,const char * name,const char * value)101 static int CheckParamValue(const WorkSpace *workSpace, const ParamTrieNode *node, const char *name, const char *value)
102 {
103 if (IS_READY_ONLY(name)) {
104 PARAM_CHECK(strlen(value) < PARAM_CONST_VALUE_LEN_MAX,
105 return PARAM_CODE_INVALID_VALUE, "Illegal param value %s", value);
106 if (node != NULL && node->dataIndex != 0) {
107 PARAM_LOGE("Read-only param was already set %s", name);
108 return PARAM_CODE_READ_ONLY;
109 }
110 } else {
111 // 限制非read only的参数,防止参数值修改后,原空间不能保存
112 PARAM_CHECK(strlen(value) < PARAM_VALUE_LEN_MAX,
113 return PARAM_CODE_INVALID_VALUE, "Illegal param value %s", value);
114 }
115 return 0;
116 }
117
WriteParam(const WorkSpace * workSpace,const char * name,const char * value,uint32_t * dataIndex,int onlyAdd)118 int WriteParam(const WorkSpace *workSpace, const char *name, const char *value, uint32_t *dataIndex, int onlyAdd)
119 {
120 PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid workSpace");
121 PARAM_CHECK(value != NULL && name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid name or value");
122 ParamTrieNode *node = FindTrieNode(workSpace, name, strlen(name), NULL);
123 int ret = CheckParamValue(workSpace, node, name, value);
124 PARAM_CHECK(ret == 0, return ret, "Invalid param value param: %s=%s", name, value);
125 if (node != NULL && node->dataIndex != 0) {
126 if (dataIndex != NULL) {
127 *dataIndex = node->dataIndex;
128 }
129 if (onlyAdd) {
130 return 0;
131 }
132 return UpdateParam(workSpace, &node->dataIndex, name, value);
133 }
134 return AddParam((WorkSpace *)workSpace, name, value, dataIndex);
135 }
136
AddSecurityLabel(const ParamAuditData * auditData,void * context)137 PARAM_STATIC int AddSecurityLabel(const ParamAuditData *auditData, void *context)
138 {
139 PARAM_CHECK(auditData != NULL && auditData->name != NULL, return -1, "Invalid auditData");
140 PARAM_CHECK(context != NULL, return -1, "Invalid context");
141 ParamWorkSpace *workSpace = (ParamWorkSpace *)context;
142 int ret = CheckParamName(auditData->name, 1);
143 PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", auditData->name);
144
145 ParamTrieNode *node = FindTrieNode(&workSpace->paramSpace, auditData->name, strlen(auditData->name), NULL);
146 if (node == NULL) {
147 node = AddTrieNode(&workSpace->paramSpace, auditData->name, strlen(auditData->name));
148 }
149 PARAM_CHECK(node != NULL, return PARAM_CODE_REACHED_MAX, "Failed to add node %s", auditData->name);
150 if (node->labelIndex == 0) { // can not support update for label
151 uint32_t offset = AddParamSecruityNode(&workSpace->paramSpace, auditData);
152 PARAM_CHECK(offset != 0, return PARAM_CODE_REACHED_MAX, "Failed to add label");
153 SaveIndex(&node->labelIndex, offset);
154 } else {
155 #ifdef STARTUP_INIT_TEST
156 ParamSecruityNode *label = (ParamSecruityNode *)GetTrieNode(&workSpace->paramSpace, node->labelIndex);
157 label->mode = auditData->dacData.mode;
158 label->uid = auditData->dacData.uid;
159 label->gid = auditData->dacData.gid;
160 #endif
161 PARAM_LOGE("Error, repeate to add label for name %s", auditData->name);
162 }
163 PARAM_LOGV("AddSecurityLabel label gid %d uid %d mode %o name: %s", auditData->dacData.gid, auditData->dacData.uid,
164 auditData->dacData.mode, auditData->name);
165 return 0;
166 }
167
BuildKey(ParamWorkSpace * workSpace,const char * format,...)168 static char *BuildKey(ParamWorkSpace *workSpace, const char *format, ...)
169 {
170 va_list vargs;
171 va_start(vargs, format);
172 size_t buffSize = sizeof(workSpace->buffer);
173 int len = vsnprintf_s(workSpace->buffer, buffSize, buffSize - 1, format, vargs);
174 va_end(vargs);
175 if (len > 0 && (size_t)len < buffSize) {
176 workSpace->buffer[len] = '\0';
177 for (int i = 0; i < len; i++) {
178 if (workSpace->buffer[i] == '|') {
179 workSpace->buffer[i] = '\0';
180 }
181 }
182 return workSpace->buffer;
183 }
184 return NULL;
185 }
186
GetServiceCtrlName(ParamWorkSpace * workSpace,const char * name,const char * value)187 static char *GetServiceCtrlName(ParamWorkSpace *workSpace, const char *name, const char *value)
188 {
189 static char *ctrlParam[] = {
190 "ohos.ctl.start",
191 "ohos.ctl.stop"
192 };
193 static char *installParam[] = {
194 "ohos.servicectrl."
195 };
196 static char *powerCtrlArg[][2] = {
197 {"reboot,shutdown", "reboot.shutdown"},
198 {"reboot,updater", "reboot.updater"},
199 {"reboot,flashd", "reboot.flashd"},
200 {"reboot", "reboot"},
201 };
202 char *key = NULL;
203 if (strcmp("ohos.startup.powerctrl", name) == 0) {
204 for (size_t i = 0; i < ARRAY_LENGTH(powerCtrlArg); i++) {
205 if (strncmp(value, powerCtrlArg[i][0], strlen(powerCtrlArg[i][0])) == 0) {
206 return BuildKey(workSpace, "%s%s", OHOS_SERVICE_CTRL_PREFIX, powerCtrlArg[i][1]);
207 }
208 }
209 return key;
210 }
211 for (size_t i = 0; i < ARRAY_LENGTH(ctrlParam); i++) {
212 if (strcmp(name, ctrlParam[i]) == 0) {
213 return BuildKey(workSpace, "%s%s", OHOS_SERVICE_CTRL_PREFIX, value);
214 }
215 }
216
217 for (size_t i = 0; i < ARRAY_LENGTH(installParam); i++) {
218 if (strncmp(name, installParam[i], strlen(installParam[i])) == 0) {
219 return BuildKey(workSpace, "%s.%s", name, value);
220 }
221 }
222 return key;
223 }
224
CheckAndSendTrigger(ParamWorkSpace * workSpace,uint32_t dataIndex,const char * name,const char * value)225 static void CheckAndSendTrigger(ParamWorkSpace *workSpace, uint32_t dataIndex, const char *name, const char *value)
226 {
227 ParamNode *entry = (ParamNode *)GetTrieNode(&workSpace->paramSpace, dataIndex);
228 PARAM_CHECK(entry != NULL, return, "Failed to get data %s ", name);
229 uint32_t trigger = 1;
230 if ((atomic_load_explicit(&entry->commitId, memory_order_relaxed) & PARAM_FLAGS_TRIGGED) != PARAM_FLAGS_TRIGGED) {
231 trigger = (CheckAndMarkTrigger(TRIGGER_PARAM, name) != 0) ? 1 : 0;
232 }
233 if (trigger) {
234 atomic_store_explicit(&entry->commitId,
235 atomic_load_explicit(&entry->commitId, memory_order_relaxed) | PARAM_FLAGS_TRIGGED, memory_order_release);
236 // notify event to process trigger
237 PostParamTrigger(EVENT_TRIGGER_PARAM, name, value);
238 }
239
240 int wait = 1;
241 if ((atomic_load_explicit(&entry->commitId, memory_order_relaxed) & PARAM_FLAGS_WAITED) != PARAM_FLAGS_WAITED) {
242 wait = (CheckAndMarkTrigger(TRIGGER_PARAM_WAIT, name) != 0) ? 1 : 0;
243 }
244 if (wait) {
245 atomic_store_explicit(&entry->commitId,
246 atomic_load_explicit(&entry->commitId, memory_order_relaxed) | PARAM_FLAGS_WAITED, memory_order_release);
247 PostParamTrigger(EVENT_TRIGGER_PARAM_WAIT, name, value);
248 }
249 PostParamTrigger(EVENT_TRIGGER_PARAM_WATCH, name, value);
250 }
251
SystemSetParam(const char * name,const char * value,const ParamSecurityLabel * srcLabel)252 static int SystemSetParam(const char *name, const char *value, const ParamSecurityLabel *srcLabel)
253 {
254 PARAM_LOGV("SystemSetParam name %s value: %s", name, value);
255 int ret = CheckParamName(name, 0);
256 PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", name);
257 char *key = GetServiceCtrlName(&g_paramWorkSpace, name, value);
258 if (srcLabel != NULL) {
259 ret = CheckParamPermission(&g_paramWorkSpace, srcLabel, (key == NULL) ? name : key, DAC_WRITE);
260 }
261 PARAM_CHECK(ret == 0, return ret, "Forbit to set parameter %s", name);
262
263 if (key != NULL) { // ctrl param
264 ret = CheckParamValue(&g_paramWorkSpace.paramSpace, NULL, name, value);
265 PARAM_CHECK(ret == 0, return ret, "Invalid param value param: %s=%s", name, value);
266 PostParamTrigger(EVENT_TRIGGER_PARAM, name, value);
267 } else {
268 uint32_t dataIndex = 0;
269 ret = WriteParam(&g_paramWorkSpace.paramSpace, name, value, &dataIndex, 0);
270 PARAM_CHECK(ret == 0, return ret, "Failed to set param %d name %s %s", ret, name, value);
271 ret = WritePersistParam(&g_paramWorkSpace, name, value);
272 PARAM_CHECK(ret == 0, return ret, "Failed to set persist param name %s", name);
273 CheckAndSendTrigger(&g_paramWorkSpace, dataIndex, name, value);
274 }
275 return ret;
276 }
277
SendResponseMsg(ParamTaskPtr worker,const ParamMessage * msg,int result)278 static int SendResponseMsg(ParamTaskPtr worker, const ParamMessage *msg, int result)
279 {
280 ParamResponseMessage *response = NULL;
281 response = (ParamResponseMessage *)CreateParamMessage(msg->type, msg->key, sizeof(ParamResponseMessage));
282 PARAM_CHECK(response != NULL, return PARAM_CODE_ERROR, "Failed to alloc memory for response");
283 response->msg.id.msgId = msg->id.msgId;
284 response->result = result;
285 response->msg.msgSize = sizeof(ParamResponseMessage);
286 ParamTaskSendMsg(worker, (ParamMessage *)response);
287 return 0;
288 }
289
SendWatcherNotifyMessage(const TriggerExtInfo * extData,const char * content,uint32_t size)290 static int SendWatcherNotifyMessage(const TriggerExtInfo *extData, const char *content, uint32_t size)
291 {
292 PARAM_CHECK(content != NULL, return -1, "Invalid content");
293 PARAM_CHECK(extData != NULL && extData->stream != NULL, return -1, "Invalid extData");
294 uint32_t msgSize = sizeof(ParamMessage) + PARAM_ALIGN(strlen(content) + 1);
295 ParamMessage *msg = (ParamMessage *)CreateParamMessage(MSG_NOTIFY_PARAM, "*", msgSize);
296 PARAM_CHECK(msg != NULL, return -1, "Failed to create msg ");
297
298 uint32_t offset = 0;
299 int ret;
300 char *tmp = strstr(content, "=");
301 if (tmp != NULL) {
302 ret = strncpy_s(msg->key, sizeof(msg->key) - 1, content, tmp - content);
303 PARAM_CHECK(ret == 0, free(msg);
304 return -1, "Failed to fill value");
305 tmp++;
306 ret = FillParamMsgContent(msg, &offset, PARAM_VALUE, tmp, strlen(tmp));
307 PARAM_CHECK(ret == 0, free(msg);
308 return -1, "Failed to fill value");
309 } else if (content != NULL && strlen(content) > 0) {
310 ret = FillParamMsgContent(msg, &offset, PARAM_VALUE, content, strlen(content));
311 PARAM_CHECK(ret == 0, free(msg);
312 return -1, "Failed to fill value");
313 }
314
315 msg->id.msgId = 0;
316 if (extData->type == TRIGGER_PARAM_WAIT) {
317 msg->id.msgId = extData->info.waitInfo.waitId;
318 } else {
319 msg->id.msgId = extData->info.watchInfo.watchId;
320 }
321 msg->msgSize = sizeof(ParamMessage) + offset;
322 PARAM_LOGV("SendWatcherNotifyMessage cmd %s, id %d msgSize %d para: %s",
323 (extData->type == TRIGGER_PARAM_WAIT) ? "wait" : "watcher",
324 msg->id.msgId, msg->msgSize, content);
325 ParamTaskSendMsg(extData->stream, msg);
326 return 0;
327 }
328
HandleParamSet(const ParamTaskPtr worker,const ParamMessage * msg)329 static int HandleParamSet(const ParamTaskPtr worker, const ParamMessage *msg)
330 {
331 uint32_t offset = 0;
332 ParamMsgContent *valueContent = GetNextContent(msg, &offset);
333 PARAM_CHECK(valueContent != NULL, return -1, "Invalid msg for %s", msg->key);
334 int ret;
335 ParamMsgContent *lableContent = GetNextContent(msg, &offset);
336 ParamSecurityLabel *srcLabel = NULL;
337 if (lableContent != NULL && lableContent->contentSize != 0) {
338 PARAM_CHECK(g_paramWorkSpace.paramSecurityOps.securityDecodeLabel != NULL,
339 return -1, "Can not get decode function");
340 ret = g_paramWorkSpace.paramSecurityOps.securityDecodeLabel(&srcLabel,
341 lableContent->content, lableContent->contentSize);
342 PARAM_CHECK(ret == 0, return ret,
343 "Failed to decode param %d name %s %s", ret, msg->key, valueContent->content);
344 }
345 if (srcLabel != NULL) {
346 struct ucred cr = {-1, -1, -1};
347 socklen_t crSize = sizeof(cr);
348 if (getsockopt(LE_GetSocketFd(worker), SOL_SOCKET, SO_PEERCRED, &cr, &crSize) < 0) {
349 PARAM_LOGE("Failed to get opt %d", errno);
350 return SendResponseMsg(worker, msg, -1);
351 }
352 srcLabel->cred.uid = cr.uid;
353 srcLabel->cred.pid = cr.pid;
354 srcLabel->cred.gid = cr.gid;
355 }
356 ret = SystemSetParam(msg->key, valueContent->content, srcLabel);
357 if (srcLabel != NULL && g_paramWorkSpace.paramSecurityOps.securityFreeLabel != NULL) {
358 g_paramWorkSpace.paramSecurityOps.securityFreeLabel(srcLabel);
359 }
360 return SendResponseMsg(worker, msg, ret);
361 }
362
CheckMatchParamWait(const ParamWorkSpace * worksapce,const char * name,const char * value)363 static ParamNode *CheckMatchParamWait(const ParamWorkSpace *worksapce, const char *name, const char *value)
364 {
365 uint32_t nameLength = strlen(name);
366 ParamTrieNode *node = FindTrieNode(&worksapce->paramSpace, name, nameLength, NULL);
367 if (node == NULL || node->dataIndex == 0) {
368 return NULL;
369 }
370 ParamNode *param = (ParamNode *)GetTrieNode(&worksapce->paramSpace, node->dataIndex);
371 if (param == NULL) {
372 return NULL;
373 }
374 if ((param->keyLength != nameLength) || (strncmp(param->data, name, nameLength) != 0)) { // compare name
375 return NULL;
376 }
377 atomic_store_explicit(¶m->commitId,
378 atomic_load_explicit(¶m->commitId, memory_order_relaxed) | PARAM_FLAGS_WAITED, memory_order_release);
379 if ((strncmp(value, "*", 1) == 0) || (strcmp(param->data + nameLength + 1, value) == 0)) { // compare value
380 return param;
381 }
382 char *tmp = strstr(value, "*");
383 if (tmp != NULL && (strncmp(param->data + nameLength + 1, value, tmp - value) == 0)) {
384 return param;
385 }
386 return NULL;
387 }
388
AddWatchNode(struct tagTriggerNode_ * trigger,const struct TriggerExtInfo_ * extInfo)389 static int32_t AddWatchNode(struct tagTriggerNode_ *trigger, const struct TriggerExtInfo_ *extInfo)
390 {
391 ParamWatcher *watcher = NULL;
392 if (extInfo != NULL && extInfo->stream != NULL) {
393 watcher = (ParamWatcher *)ParamGetTaskUserData(extInfo->stream);
394 }
395 PARAM_CHECK(watcher != NULL, return -1, "Failed to get param watcher data");
396 if (extInfo->type == TRIGGER_PARAM_WAIT) {
397 WaitNode *node = (WaitNode *)trigger;
398 ListInit(&node->item);
399 node->timeout = extInfo->info.waitInfo.timeout;
400 node->stream = extInfo->stream;
401 node->waitId = extInfo->info.waitInfo.waitId;
402 ListAddTail(&watcher->triggerHead, &node->item);
403 } else {
404 WatchNode *node = (WatchNode *)trigger;
405 ListInit(&node->item);
406 node->watchId = extInfo->info.watchInfo.watchId;
407 ListAddTail(&watcher->triggerHead, &node->item);
408 }
409 return 0;
410 }
411
AddWatcherTrigger(int triggerType,const char * condition,const TriggerExtInfo * extData)412 static TriggerNode *AddWatcherTrigger(int triggerType, const char *condition, const TriggerExtInfo *extData)
413 {
414 TriggerWorkSpace *workSpace = GetTriggerWorkSpace();
415 TriggerHeader *header = (TriggerHeader *)&workSpace->triggerHead[extData->type];
416 return header->addTrigger(workSpace, condition, extData);
417 }
418
ExecuteWatchTrigger_(const struct tagTriggerNode_ * trigger,const char * content,uint32_t size)419 static int32_t ExecuteWatchTrigger_(const struct tagTriggerNode_ *trigger, const char *content, uint32_t size)
420 {
421 TriggerExtInfo extData = {};
422 extData.type = trigger->type;
423 if (trigger->type == TRIGGER_PARAM_WAIT) {
424 WaitNode *node = (WaitNode *)trigger;
425 extData.stream = node->stream;
426 extData.info.waitInfo.waitId = node->waitId;
427 extData.info.waitInfo.timeout = node->timeout;
428 } else {
429 WatchNode *node = (WatchNode *)trigger;
430 extData.stream = g_paramWorkSpace.watcherTask;
431 extData.info.watchInfo.watchId = node->watchId;
432 }
433 if (content == NULL) {
434 return SendWatcherNotifyMessage(&extData, "", 0);
435 }
436 return SendWatcherNotifyMessage(&extData, content, size);
437 }
438
HandleParamWaitAdd(const ParamWorkSpace * worksapce,const ParamTaskPtr worker,const ParamMessage * msg)439 static int HandleParamWaitAdd(const ParamWorkSpace *worksapce, const ParamTaskPtr worker, const ParamMessage *msg)
440 {
441 PARAM_CHECK(msg != NULL, return -1, "Invalid message");
442 uint32_t offset = 0;
443 uint32_t timeout = DEFAULT_PARAM_WAIT_TIMEOUT;
444 ParamMsgContent *valueContent = GetNextContent(msg, &offset);
445 PARAM_CHECK(valueContent != NULL, return -1, "Invalid msg");
446 PARAM_CHECK(valueContent->contentSize <= PARAM_CONST_VALUE_LEN_MAX, return -1, "Invalid msg");
447 ParamMsgContent *timeoutContent = GetNextContent(msg, &offset);
448 if (timeoutContent != NULL) {
449 timeout = *((uint32_t *)(timeoutContent->content));
450 }
451
452 PARAM_LOGV("HandleParamWaitAdd name %s timeout %d", msg->key, timeout);
453 TriggerExtInfo extData = {};
454 extData.addNode = AddWatchNode;
455 extData.type = TRIGGER_PARAM_WAIT;
456 extData.stream = worker;
457 extData.info.waitInfo.waitId = msg->id.watcherId;
458 extData.info.waitInfo.timeout = timeout;
459 // first check match, if match send response to client
460 ParamNode *param = CheckMatchParamWait(worksapce, msg->key, valueContent->content);
461 if (param != NULL) {
462 SendWatcherNotifyMessage(&extData, param->data, param->valueLength);
463 return 0;
464 }
465
466 uint32_t buffSize = strlen(msg->key) + valueContent->contentSize + 1 + 1;
467 char *condition = calloc(1, buffSize);
468 PARAM_CHECK(condition != NULL, return -1, "Failed to create condition for %s", msg->key);
469 int ret = sprintf_s(condition, buffSize - 1, "%s=%s", msg->key, valueContent->content);
470 PARAM_CHECK(ret > EOK, free(condition);
471 return -1, "Failed to copy name for %s", msg->key);
472 TriggerNode *trigger = AddWatcherTrigger(TRIGGER_PARAM_WAIT, condition, &extData);
473 PARAM_CHECK(trigger != NULL, free(condition);
474 return -1, "Failed to add trigger for %s", msg->key);
475 free(condition);
476 if (g_paramWorkSpace.timer == NULL) {
477 ret = ParamTimerCreate(&g_paramWorkSpace.timer, TimerCallback, &g_paramWorkSpace);
478 PARAM_CHECK(ret == 0, return 0, "Failed to create timer %s", msg->key);
479 ret = ParamTimerStart(g_paramWorkSpace.timer, MS_UNIT, (uint64_t)-1);
480 PARAM_CHECK(ret == 0,
481 ParamTaskClose(g_paramWorkSpace.timer);
482 g_paramWorkSpace.timer = NULL;
483 return 0, "Failed to set timer %s", msg->key);
484 PARAM_LOGI("Start timer %p", g_paramWorkSpace.timer);
485 }
486 return 0;
487 }
488
HandleParamWatcherAdd(ParamWorkSpace * workSpace,const ParamTaskPtr worker,const ParamMessage * msg)489 static int HandleParamWatcherAdd(ParamWorkSpace *workSpace, const ParamTaskPtr worker, const ParamMessage *msg)
490 {
491 PARAM_CHECK(msg != NULL, return -1, "Invalid message");
492 PARAM_CHECK((g_paramWorkSpace.watcherTask == NULL) ||
493 (g_paramWorkSpace.watcherTask == worker), return -1, "Invalid watcher worker");
494 g_paramWorkSpace.watcherTask = worker;
495 TriggerExtInfo extData = {};
496 extData.type = TRIGGER_PARAM_WATCH;
497 extData.addNode = AddWatchNode;
498 extData.stream = worker;
499 extData.info.watchInfo.watchId = msg->id.watcherId;
500 TriggerNode *trigger = AddWatcherTrigger(TRIGGER_PARAM_WATCH, msg->key, &extData);
501 if (trigger == NULL) {
502 PARAM_LOGE("Failed to add trigger for %s", msg->key);
503 return SendResponseMsg(worker, msg, -1);
504 }
505 PARAM_LOGV("HandleParamWatcherAdd name %s watcher: %d", msg->key, msg->id.watcherId);
506 return SendResponseMsg(worker, msg, 0);
507 }
508
HandleParamWatcherDel(ParamWorkSpace * workSpace,const ParamTaskPtr worker,const ParamMessage * msg)509 static int HandleParamWatcherDel(ParamWorkSpace *workSpace, const ParamTaskPtr worker, const ParamMessage *msg)
510 {
511 PARAM_CHECK(msg != NULL, return -1, "Invalid message");
512 PARAM_LOGV("HandleParamWatcherDel name %s watcher: %d", msg->key, msg->id.watcherId);
513 DelWatchTrigger(TRIGGER_PARAM_WATCH, (const void *)&msg->id.watcherId);
514 return SendResponseMsg(worker, msg, 0);
515 }
516
ProcessMessage(const ParamTaskPtr worker,const ParamMessage * msg)517 PARAM_STATIC int ProcessMessage(const ParamTaskPtr worker, const ParamMessage *msg)
518 {
519 PARAM_CHECK((msg != NULL) && (msg->msgSize >= sizeof(ParamMessage)), return -1, "Invalid msg");
520 PARAM_CHECK(worker != NULL, return -1, "Invalid worker");
521 int ret = PARAM_CODE_INVALID_PARAM;
522 switch (msg->type) {
523 case MSG_SET_PARAM:
524 ret = HandleParamSet(worker, msg);
525 break;
526 case MSG_WAIT_PARAM:
527 ret = HandleParamWaitAdd(&g_paramWorkSpace, worker, msg);
528 break;
529 case MSG_ADD_WATCHER:
530 ret = HandleParamWatcherAdd(&g_paramWorkSpace, worker, msg);
531 break;
532 case MSG_DEL_WATCHER:
533 ret = HandleParamWatcherDel(&g_paramWorkSpace, worker, msg);
534 break;
535 default:
536 break;
537 }
538 PARAM_CHECK(ret == 0, return -1, "Failed to process message ret %d", ret);
539 return 0;
540 }
541
LoadOneParam_(char * line,uint32_t mode,const char * exclude[],uint32_t count)542 static int LoadOneParam_(char *line, uint32_t mode, const char *exclude[], uint32_t count)
543 {
544 char *name;
545 char *value;
546 char *pos;
547
548 // Skip spaces
549 name = line;
550 while (isspace(*name) && (*name != '\0')) {
551 name++;
552 }
553 // Empty line
554 if (*name == '\0') {
555 return 0;
556 }
557 // Comment line
558 if (*name == '#') {
559 return 0;
560 }
561
562 value = name;
563 // find the first delimiter '='
564 while (*value != '\0') {
565 if (*value == '=') {
566 (*value) = '\0';
567 value = value + 1;
568 break;
569 }
570 value++;
571 }
572
573 // empty name, just ignore this line
574 if (*name == '\0') {
575 return 0;
576 }
577
578 // Trim the ending spaces of name
579 pos = value - 1;
580 pos -= 1;
581 while (isspace(*pos) && pos > name) {
582 (*pos) = '\0';
583 pos--;
584 }
585
586 // Filter excluded parameters
587 for (uint32_t i = 0; i < count; i++) {
588 if (strncmp(name, exclude[i], strlen(exclude[i])) == 0) {
589 return 0;
590 }
591 }
592
593 // Skip spaces for value
594 while (isspace(*value) && (*value != '\0')) {
595 value++;
596 }
597
598 // Trim the ending spaces of value
599 pos = value + strlen(value);
600 pos--;
601 while (isspace(*pos) && pos > value) {
602 (*pos) = '\0';
603 pos--;
604 }
605
606 // Strip starting and ending " for value
607 if ((*value == '"') && (pos > value) && (*pos == '"')) {
608 value = value + 1;
609 *pos = '\0';
610 }
611
612 int ret = CheckParamName(name, 0);
613 // Invalid name, just ignore
614 if (ret != 0) {
615 return 0;
616 }
617 PARAM_LOGV("Add default parameter [%s] [%s]", name, value);
618 return WriteParam(&g_paramWorkSpace.paramSpace,
619 name, value, NULL, mode & LOAD_PARAM_ONLY_ADD);
620 }
621
LoadDefaultParam_(const char * fileName,uint32_t mode,const char * exclude[],uint32_t count)622 static int LoadDefaultParam_(const char *fileName, uint32_t mode, const char *exclude[], uint32_t count)
623 {
624 // max length for each line of para files: max name length + max value length + spaces
625 #define PARAM_LINE_MAX_LENGTH (PARAM_NAME_LEN_MAX + PARAM_CONST_VALUE_LEN_MAX + 10)
626
627 uint32_t paramNum = 0;
628 FILE *fp = fopen(fileName, "r");
629 if (fp == NULL) {
630 return -1;
631 }
632
633 char *buff = calloc(1, PARAM_LINE_MAX_LENGTH);
634 if (buff == NULL) {
635 (void)fclose(fp);
636 return -1;
637 }
638
639 while (fgets(buff, PARAM_LINE_MAX_LENGTH, fp) != NULL) {
640 buff[PARAM_LINE_MAX_LENGTH - 1] = '\0';
641
642 int ret = LoadOneParam_(buff, mode, exclude, count);
643 PARAM_CHECK(ret == 0, continue, "Failed to set param %d %s", ret, buff);
644 paramNum++;
645 }
646 (void)fclose(fp);
647 free(buff);
648 PARAM_LOGI("Load parameters success %s total %u", fileName, paramNum);
649 return 0;
650 }
651
OnIncomingConnect(LoopHandle loop,TaskHandle server)652 PARAM_STATIC int OnIncomingConnect(LoopHandle loop, TaskHandle server)
653 {
654 ParamStreamInfo info = {};
655 info.server = NULL;
656 info.close = OnClose;
657 info.recvMessage = ProcessMessage;
658 info.incomingConnect = NULL;
659 ParamTaskPtr client = NULL;
660 int ret = ParamStreamCreate(&client, server, &info, sizeof(ParamWatcher));
661 PARAM_CHECK(ret == 0, return -1, "Failed to create client");
662
663 ParamWatcher *watcher = (ParamWatcher *)ParamGetTaskUserData(client);
664 PARAM_CHECK(watcher != NULL, return -1, "Failed to get watcher");
665 ListInit(&watcher->triggerHead);
666 watcher->stream = client;
667 #ifdef STARTUP_INIT_TEST
668 GetParamWorkSpace()->watcherTask = client;
669 #endif
670 return 0;
671 }
672
GetParamValueFromBuffer(const char * name,const char * buffer,char * value,int length)673 static int GetParamValueFromBuffer(const char *name, const char *buffer, char *value, int length)
674 {
675 size_t bootLen = strlen(OHOS_BOOT);
676 const char *tmpName = name + bootLen;
677 int ret = GetProcCmdlineValue(tmpName, buffer, value, length);
678 return ret;
679 }
680
LoadParamFromCmdLine(void)681 static int LoadParamFromCmdLine(void)
682 {
683 int ret;
684 static const char *cmdLines[] = {
685 OHOS_BOOT"hardware",
686 OHOS_BOOT"bootgroup",
687 #ifdef STARTUP_INIT_TEST
688 OHOS_BOOT"mem",
689 OHOS_BOOT"console",
690 OHOS_BOOT"mmz",
691 OHOS_BOOT"androidboot.selinux",
692 OHOS_BOOT"init",
693 OHOS_BOOT"root",
694 OHOS_BOOT"uuid",
695 OHOS_BOOT"rootfstype",
696 OHOS_BOOT"blkdevparts"
697 #endif
698 };
699 char *data = ReadFileData(PARAM_CMD_LINE);
700 PARAM_CHECK(data != NULL, return -1, "Failed to read file %s", PARAM_CMD_LINE);
701 char *value = calloc(1, PARAM_CONST_VALUE_LEN_MAX + 1);
702 PARAM_CHECK(value != NULL, free(data);
703 return -1, "Failed to read file %s", PARAM_CMD_LINE);
704
705 for (size_t i = 0; i < ARRAY_LENGTH(cmdLines); i++) {
706 #ifdef BOOT_EXTENDED_CMDLINE
707 ret = GetParamValueFromBuffer(cmdLines[i], BOOT_EXTENDED_CMDLINE, value, PARAM_CONST_VALUE_LEN_MAX);
708 if (ret != 0) {
709 ret = GetParamValueFromBuffer(cmdLines[i], data, value, PARAM_CONST_VALUE_LEN_MAX);
710 }
711 #else
712 ret = GetParamValueFromBuffer(cmdLines[i], data, value, PARAM_CONST_VALUE_LEN_MAX);
713 #endif
714 if (ret == 0) {
715 PARAM_LOGV("Add param from cmdline %s %s", cmdLines[i], value);
716 ret = CheckParamName(cmdLines[i], 0);
717 PARAM_CHECK(ret == 0, break, "Invalid name %s", cmdLines[i]);
718 PARAM_LOGV("**** cmdLines[%d] %s, value %s", i, cmdLines[i], value);
719 ret = WriteParam(&g_paramWorkSpace.paramSpace, cmdLines[i], value, NULL, 0);
720 PARAM_CHECK(ret == 0, break, "Failed to write param %s %s", cmdLines[i], value);
721 } else {
722 PARAM_LOGE("Can not find arrt %s", cmdLines[i]);
723 }
724 }
725 PARAM_LOGV("Parse cmdline finish %s", PARAM_CMD_LINE);
726 free(data);
727 free(value);
728 return 0;
729 }
730
SystemWriteParam(const char * name,const char * value)731 int SystemWriteParam(const char *name, const char *value)
732 {
733 PARAM_CHECK(name != NULL && value != NULL, return -1, "The name is null");
734 return SystemSetParam(name, value, g_paramWorkSpace.securityLabel);
735 }
736
SystemReadParam(const char * name,char * value,unsigned int * len)737 int SystemReadParam(const char *name, char *value, unsigned int *len)
738 {
739 PARAM_CHECK(name != NULL && len != NULL, return -1, "The name is null");
740 ParamHandle handle = 0;
741 int ret = ReadParamWithCheck(&g_paramWorkSpace, name, DAC_READ, &handle);
742 if (ret == 0) {
743 ret = ReadParamValue(&g_paramWorkSpace, handle, value, len);
744 }
745 return ret;
746 }
747
LoadPersistParams(void)748 int LoadPersistParams(void)
749 {
750 return LoadPersistParam(&g_paramWorkSpace);
751 }
752
ProcessParamFile(const char * fileName,void * context)753 static int ProcessParamFile(const char *fileName, void *context)
754 {
755 static const char *exclude[] = {"ctl.", "selinux.restorecon_recursive"};
756 uint32_t mode = *(int *)context;
757 return LoadDefaultParam_(fileName, mode, exclude, ARRAY_LENGTH(exclude));
758 }
759
LoadDefaultParams(const char * fileName,uint32_t mode)760 int LoadDefaultParams(const char *fileName, uint32_t mode)
761 {
762 PARAM_CHECK(fileName != NULL, return -1, "Invalid fielname for load");
763 if (!PARAM_TEST_FLAG(g_paramWorkSpace.flags, WORKSPACE_FLAGS_INIT)) {
764 return PARAM_CODE_NOT_INIT;
765 }
766 PARAM_LOGI("load default parameters %s.", fileName);
767 int ret = 0;
768 struct stat st;
769 if ((stat(fileName, &st) == 0) && !S_ISDIR(st.st_mode)) {
770 ret = ProcessParamFile(fileName, &mode);
771 } else {
772 ret = ReadFileInDir(fileName, ".para", ProcessParamFile, &mode);
773 }
774
775 // load security label
776 ParamSecurityOps *ops = &g_paramWorkSpace.paramSecurityOps;
777 if (ops->securityGetLabel != NULL) {
778 ret = ops->securityGetLabel(AddSecurityLabel, fileName, (void *)&g_paramWorkSpace);
779 }
780 return ret;
781 }
782
InitParamService(void)783 void InitParamService(void)
784 {
785 PARAM_LOGI("InitParamService pipe: %s.", PIPE_NAME);
786 CheckAndCreateDir(PIPE_NAME);
787 int ret = InitParamWorkSpace(&g_paramWorkSpace, 0);
788 PARAM_CHECK(ret == 0, return, "Init parameter workspace fail");
789 ret = InitPersistParamWorkSpace(&g_paramWorkSpace);
790 PARAM_CHECK(ret == 0, return, "Init persist parameter workspace fail");
791 if (g_paramWorkSpace.serverTask == NULL) {
792 ParamStreamInfo info = {};
793 info.server = PIPE_NAME;
794 info.close = NULL;
795 info.recvMessage = NULL;
796 info.incomingConnect = OnIncomingConnect;
797 ret = ParamServerCreate(&g_paramWorkSpace.serverTask, &info);
798 PARAM_CHECK(ret == 0, return, "Failed to create server");
799 }
800 ret = InitTriggerWorkSpace();
801 PARAM_CHECK(ret == 0, return, "Failed to init trigger");
802
803 RegisterTriggerExec(TRIGGER_PARAM_WAIT, ExecuteWatchTrigger_);
804 RegisterTriggerExec(TRIGGER_PARAM_WATCH, ExecuteWatchTrigger_);
805 ParamAuditData auditData = {};
806 auditData.name = "#";
807 auditData.label = NULL;
808 auditData.dacData.gid = getegid();
809 auditData.dacData.uid = geteuid();
810 auditData.dacData.mode = DAC_ALL_PERMISSION;
811 ret = AddSecurityLabel(&auditData, (void *)&g_paramWorkSpace);
812 PARAM_CHECK(ret == 0, return, "Failed to add default dac label");
813
814 // 读取cmdline的参数
815 LoadParamFromCmdLine();
816 }
817
StartParamService(void)818 int StartParamService(void)
819 {
820 return ParamServiceStart();
821 }
822
StopParamService(void)823 void StopParamService(void)
824 {
825 PARAM_LOGI("StopParamService.");
826 ClosePersistParamWorkSpace();
827 CloseParamWorkSpace(&g_paramWorkSpace);
828 CloseTriggerWorkSpace();
829 ParamTaskClose(g_paramWorkSpace.serverTask);
830 g_paramWorkSpace.serverTask = NULL;
831 ParamServiceStop();
832 }
833
GetParamWorkSpace(void)834 ParamWorkSpace *GetParamWorkSpace(void)
835 {
836 return &g_paramWorkSpace;
837 }
838
DumpParametersAndTriggers(void)839 void DumpParametersAndTriggers(void)
840 {
841 DumpParameters(&g_paramWorkSpace, 1);
842 if (GetTriggerWorkSpace() != NULL) {
843 DumpTrigger(GetTriggerWorkSpace());
844 }
845 }
846