• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&param->commitId,
378         atomic_load_explicit(&param->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