• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <ctype.h>
16 #include <errno.h>
17 #include <limits.h>
18 
19 #include "param_manager.h"
20 #include "param_trie.h"
21 #ifdef SUPPORT_PARAM_LOAD_HOOK
22 #include "init_module_engine.h"
23 #endif
24 #include "securec.h"
25 #include "init_cmds.h"
26 #include "init_param.h"
27 
28 /**
29  * Loading system parameter from /proc/cmdline by the following rules:
30  *   1) reserved cmdline with or without ohos.boot. prefix listed in CmdlineIterator
31         will be processed by the specified processor
32  *   2) cmdline not listed in CmdlineIterator but prefixed with ohos.boot will be add by default
33  *
34  *   Special cases for sn:
35  *     a) if sn value in cmdline is started with "/", it means a file to be read as parameter value
36  *     b) if sn or ohos.boot.sn are not specified, try to generate sn by GenerateSnByDefault
37  */
38 #define OHOS_CMDLINE_PARA_PREFIX        "ohos.boot."
39 #define OHOS_CMDLINE_CONST_PARA_PREFIX  "const.product."
40 #define OHOS_CMDLINE_PARA_PREFIX_LEN    10
41 #define IMPORT_PREFIX_LEN               7
42 
43 typedef struct CmdLineInfo {
44     const char *name;
45     int (*processor)(const char *name, const char *value);
46 } CmdLineInfo;
47 
48 typedef struct CmdLineInfoContainer {
49     const CmdLineInfo *cmdLineInfo;
50     size_t cmdLineInfoSize;
51 } CmdLineInfoContainer;
52 
53 typedef struct CmdLineIteratorCtx {
54     char *cmdline;
55     bool gotSn;
56     bool *matches;
57 } CmdLineIteratorCtx;
58 
CommonDealFun(const char * name,const char * value)59 static int CommonDealFun(const char *name, const char *value)
60 {
61     int ret = 0;
62     PARAM_LOGV("Add param from cmdline %s %s", name, value);
63     ret = CheckParamName(name, 0);
64     PARAM_CHECK(ret == 0, return ret, "Invalid param name %s", name);
65     PARAM_LOGV("Param name %s, value %s", name, value);
66     ret = WriteParam(name, value, NULL, 0);
67     PARAM_CHECK(ret == 0, return ret, "Failed to write param %s %s", name, value);
68     return ret;
69 }
70 
ReadSnFromFile(const char * name,const char * file)71 static int ReadSnFromFile(const char *name, const char *file)
72 {
73     char *data = ReadFileData(file);
74     PARAM_CHECK(data != NULL, return -1, "Read sn from %s file failed!", file);
75 
76     int index = 0;
77     for (size_t i = 0; i < strlen(data); i++) {
78         // cancel \r\n
79         if (*(data + i) == '\r' || *(data + i) == '\n') {
80             break;
81         }
82         if (*(data + i) != ':') {
83             *(data + index) = *(data + i);
84             index++;
85         }
86     }
87     data[index] = '\0';
88     PARAM_LOGV("**** name %s, value %s", name, data);
89     int ret = WriteParam(name, data, NULL, 0);
90     free(data);
91     PARAM_CHECK(ret == 0, return ret, "Failed to write param %s", name);
92     return ret;
93 }
94 
95 #define OHOS_SN_PARAM_NAME OHOS_CMDLINE_PARA_PREFIX"sn"
96 
SnDealFun(const char * name,const char * value)97 static int SnDealFun(const char *name, const char *value)
98 {
99     int ret = CheckParamName(name, 0);
100     PARAM_CHECK(ret == 0, return ret, "Invalid name %s", name);
101     if (value != NULL && value[0] != '/') {
102         PARAM_LOGV("**** name %s, value %s", name, value);
103         ret = WriteParam(OHOS_SN_PARAM_NAME, value, NULL, 0);
104         PARAM_CHECK(ret == 0, return ret, "Failed to write param %s %s", name, value);
105         return ret;
106     }
107     if (value != NULL && value[0] == '/') {
108         ret = ReadSnFromFile(OHOS_SN_PARAM_NAME, value);
109         if (ret == 0) {
110             return ret;
111         }
112     }
113     return ret;
114 }
115 
Common2ConstDealFun(const char * name,const char * value)116 static int Common2ConstDealFun(const char *name, const char *value)
117 {
118     const char *tmpName;
119     tmpName = name;
120     if (strncmp(tmpName, OHOS_CMDLINE_PARA_PREFIX, OHOS_CMDLINE_PARA_PREFIX_LEN) == 0) {
121         tmpName = tmpName + OHOS_CMDLINE_PARA_PREFIX_LEN;
122     }
123     char fullName[PARAM_NAME_LEN_MAX];
124     int ret = snprintf_s(fullName, sizeof(fullName), sizeof(fullName) - 1,
125                          OHOS_CMDLINE_CONST_PARA_PREFIX"%s", tmpName);
126     PARAM_CHECK(ret > 0, return ret, "snprinf_s failed");
127     ret = CheckParamName(fullName, 0);
128     PARAM_CHECK(ret == 0, return ret, "Invalid name %s", name);
129     PARAM_LOGV("Param name %s, value %s", fullName, value);
130     ret = WriteParam(fullName, value, NULL, 0);
131     PARAM_CHECK(ret == 0, return ret, "Failed to write param %s %s", fullName, value);
132     return ret;
133 }
134 
MatchReserverCmdline(const NAME_VALUE_PAIR * nv,CmdLineIteratorCtx * ctx,const char * name,CmdLineInfoContainer * container)135 static int MatchReserverCmdline(const NAME_VALUE_PAIR* nv, CmdLineIteratorCtx *ctx, const char *name,
136                                 CmdLineInfoContainer *container)
137 {
138     const char* tmpName = name;
139     char fullName[PARAM_NAME_LEN_MAX];
140     int ret = 0;
141     const char* matched;
142 
143     // Matching reserved cmdlines
144     for (size_t i = 0; i < container->cmdLineInfoSize; i++) {
145         // Check exact match
146         if (strcmp(tmpName, (container->cmdLineInfo + i)->name) != 0) {
147             // Check if contains ".xxx" for compatibility
148             ret = snprintf_s(fullName, sizeof(fullName), sizeof(fullName) - 1, ".%s",
149                             (container->cmdLineInfo + i)->name);
150             matched = strstr(tmpName, fullName);
151             if (matched == NULL) {
152                 continue;
153             }
154             // Check if it is ended with pattern
155             if (matched[ret] != '\0') {
156                 continue;
157             }
158         }
159         ret = snprintf_s(fullName, sizeof(fullName), sizeof(fullName) - 1,
160                          OHOS_CMDLINE_PARA_PREFIX "%s", (container->cmdLineInfo + i)->name);
161         if (ret <= 0) {
162             continue;
163         }
164         if (ctx->matches[i]) {
165             return PARAM_CODE_SUCCESS;
166         }
167         bool isSnSet = ((container->cmdLineInfo + i)->processor == SnDealFun);
168         if (isSnSet && ctx->gotSn) {
169             return PARAM_CODE_SUCCESS;
170         }
171         PARAM_LOGV("proc cmdline %s matched.", fullName);
172         ret = (container->cmdLineInfo + i)->processor(fullName, nv->value);
173         if (ret == 0) {
174             ctx->matches[i] = true;
175             if (isSnSet) {
176                 ctx->gotSn = true;
177             }
178         }
179         return PARAM_CODE_SUCCESS;
180     }
181     return PARAM_CODE_NOT_FOUND;
182 }
183 
184 static const CmdLineInfo CMDLINES[] = {
185     { "hardware", CommonDealFun },
186     { "bootgroup", CommonDealFun },
187     { "reboot_reason", CommonDealFun },
188     { "bootslots", CommonDealFun },
189     { "sn", SnDealFun },
190     { "root_package", CommonDealFun },
191     { "serialno", SnDealFun },
192     { "udid", Common2ConstDealFun },
193     { "productid", Common2ConstDealFun }
194 };
195 
CmdlineIterator(const NAME_VALUE_PAIR * nv,void * context)196 static void CmdlineIterator(const NAME_VALUE_PAIR *nv, void *context)
197 {
198     CmdLineIteratorCtx *ctx = (CmdLineIteratorCtx *)context;
199     char *data = (char *)ctx->cmdline;
200 
201     data[nv->nameEnd - data] = '\0';
202     data[nv->valueEnd - data] = '\0';
203     PARAM_LOGV("proc cmdline: name [%s], value [%s]", nv->name, nv->value);
204 
205     // Get name without prefix
206     const char *name = nv->name;
207     if (strncmp(name, OHOS_CMDLINE_PARA_PREFIX, OHOS_CMDLINE_PARA_PREFIX_LEN) == 0) {
208         name = name + OHOS_CMDLINE_PARA_PREFIX_LEN;
209     }
210 
211     CmdLineInfoContainer container = { 0 };
212     container.cmdLineInfo = CMDLINES;
213     container.cmdLineInfoSize = ARRAY_LENGTH(CMDLINES);
214     if (MatchReserverCmdline(nv, ctx, name, &container) == 0) {
215         PARAM_LOGV("match reserver cmd line success, name: %s, value: %s", nv->name, nv->value);
216         return;
217     }
218     if (name == nv->name) {
219         return;
220     }
221 
222     // cmdline with prefix but not matched, add to param by default
223     PARAM_LOGI("add proc cmdline param %s by default.", nv->name);
224     CommonDealFun(nv->name, nv->value);
225 }
226 
GenerateSnByDefault(void)227 static void GenerateSnByDefault(void)
228 {
229     const char *snFileList [] = {
230         "/sys/block/mmcblk0/device/cid",
231         "/proc/bootdevice/cid"
232     };
233 
234     for (size_t i = 0; i < ARRAY_LENGTH(snFileList); i++) {
235         int ret = ReadSnFromFile(OHOS_CMDLINE_PARA_PREFIX "sn", snFileList[i]);
236         if (ret == 0) {
237             break;
238         }
239     }
240 }
241 
LoadParamFromCmdLine(void)242 INIT_LOCAL_API int LoadParamFromCmdLine(void)
243 {
244     CmdLineIteratorCtx ctx;
245 
246     ctx.gotSn = false;
247     ctx.cmdline = ReadFileData(BOOT_CMD_LINE);
248     PARAM_CHECK(ctx.cmdline != NULL, return -1, "Failed to read file %s", BOOT_CMD_LINE);
249     bool matches[ARRAY_LENGTH(CMDLINES)] = {false};
250     ctx.matches = matches;
251     IterateNameValuePairs(ctx.cmdline, CmdlineIterator, (void *)(&ctx));
252 
253     // sn is critical, it must be specified
254     if (!ctx.gotSn) {
255         PARAM_LOGE("Generate default sn now ...");
256         GenerateSnByDefault();
257     }
258 
259     free(ctx.cmdline);
260     return 0;
261 }
262 
263 /*
264  * Load parameters from files
265  */
266 
LoadSecurityLabel(const char * fileName)267 static int LoadSecurityLabel(const char *fileName)
268 {
269     ParamWorkSpace *paramSpace = GetParamWorkSpace();
270     PARAM_CHECK(paramSpace != NULL, return -1, "Invalid paramSpace");
271     PARAM_WORKSPACE_CHECK(paramSpace, return -1, "Invalid space");
272     PARAM_CHECK(fileName != NULL, return -1, "Invalid filename for load");
273 #if !(defined __LITEOS_A__ || defined __LITEOS_M__)
274     // load security label
275     ParamSecurityOps *ops = GetParamSecurityOps(PARAM_SECURITY_DAC);
276     if (ops != NULL && ops->securityGetLabel != NULL) {
277         if (ops->securityGetLabel(fileName) == PARAM_CODE_REACHED_MAX) {
278             PARAM_LOGE("[startup_failed]Load Security Lable failed! system reboot! %d", SYS_PARAM_INIT_FAILED);
279             ExecReboot("panic");
280         };
281     }
282 #endif
283     return 0;
284 }
285 
LoadOneParam_(const uint32_t * context,const char * name,const char * value)286 static int LoadOneParam_(const uint32_t *context, const char *name, const char *value)
287 {
288     uint32_t mode = *(uint32_t *)context;
289     int ret = CheckParamName(name, 0);
290     if (ret != 0) {
291         return 0;
292     }
293 
294 #ifdef SUPPORT_PARAM_LOAD_HOOK
295     PARAM_LOAD_FILTER_CTX filter;
296 
297     // Filter by hook
298     filter.name = name;
299     filter.value = value;
300     filter.ignored = 0;
301     HookMgrExecute(GetBootStageHookMgr(), INIT_PARAM_LOAD_FILTER, (void *)&filter, NULL);
302 
303     if (filter.ignored) {
304         PARAM_LOGV("Default parameter [%s] [%s] ignored", name, value);
305         return 0;
306     }
307 #endif
308 
309     PARAM_LOGV("Add default parameter [%s] [%s]", name, value);
310     return WriteParam(name, value, NULL, mode & LOAD_PARAM_ONLY_ADD);
311 }
312 
LoadFileFromImport(char * target,uint32_t mode)313 static int LoadFileFromImport(char *target, uint32_t mode)
314 {
315     if (strstr(target, ".para.dac")) {
316         LoadSecurityLabel(target);
317     } else {
318         LoadDefaultParams(target, mode);
319     }
320     return 0;
321 }
322 
323 // Content format of .import.para is "import /dir/param.para"
324 // Use ${} to pass parameter like "import /dir/${const.product.productid}.para"
LoadParamFromImport_(char * buffer,const int buffSize,uint32_t mode)325 static int LoadParamFromImport_(char *buffer, const int buffSize, uint32_t mode)
326 {
327     int spaceCount = 0;
328     while (*(buffer + IMPORT_PREFIX_LEN + spaceCount) == ' ') {
329         spaceCount++;
330     }
331     char *target = calloc(PATH_MAX, 1);
332     PARAM_CHECK(target != NULL, return -1, "Failed to alloc memory");
333     if (strncpy_s(target, buffSize, buffer + IMPORT_PREFIX_LEN + spaceCount, buffSize) != 0) {
334         PARAM_LOGE("Failed to get value of import.");
335         free(target);
336         return -1;
337     }
338     char *tmp = NULL;
339     if ((tmp = strstr(target, "\n"))) {
340         *tmp = '\0';
341     }
342     char *tmpParamValue = calloc(PARAM_VALUE_LEN_MAX + 1, sizeof(char));
343     if (tmpParamValue == NULL) {
344         PARAM_LOGE("Failed to alloc memory");
345         free(target);
346         return -1;
347     }
348     int ret = GetParamValue(target, strlen(target), tmpParamValue, PARAM_VALUE_LEN_MAX);
349     if (ret == 0) {
350         LoadFileFromImport(tmpParamValue, mode);
351     }
352     PARAM_LOGI("Load params from import %s return %d.", tmpParamValue, ret);
353     free(tmpParamValue);
354     free(target);
355     return ret;
356 }
357 
LoadParamFromImport(const char * fileName,void * context)358 static int LoadParamFromImport(const char *fileName, void *context)
359 {
360     char realPath[PATH_MAX] = "";
361     realpath(fileName, realPath);
362     FILE *fp = fopen(realPath, "r");
363     if (fp == NULL) {
364         PARAM_LOGE("Failed to open file '%s' error:%d ", fileName, errno);
365         return -1;
366     }
367 
368     const int buffSize = PATH_MAX;
369     char *buffer = malloc(buffSize);
370     PARAM_CHECK(buffer != NULL, (void)fclose(fp);
371         return -1, "Failed to alloc memory");
372 
373     uint32_t mode = *(int *)context;
374     while (fgets(buffer, buffSize, fp) != NULL) {
375         buffer[buffSize - 1] = '\0';
376         if (!strncmp(buffer, "import ", IMPORT_PREFIX_LEN)) {
377             (void)LoadParamFromImport_(buffer, buffSize, mode);
378         }
379     }
380     (void)fclose(fp);
381     free(buffer);
382     return 0;
383 }
384 
LoadDefaultParam_(const char * fileName,uint32_t mode,const char * exclude[],uint32_t count,int (* loadOneParam)(const uint32_t *,const char *,const char *))385 static int LoadDefaultParam_(const char *fileName, uint32_t mode,
386     const char *exclude[], uint32_t count, int (*loadOneParam)(const uint32_t *, const char *, const char *))
387 {
388     uint32_t paramNum = 0;
389     char realPath[PATH_MAX] = "";
390     realpath(fileName, realPath);
391     FILE *fp = fopen(realPath, "r");
392     if (fp == NULL) {
393         PARAM_LOGW("Failed to open file '%s' error:%d ", fileName, errno);
394         return -1;
395     }
396 
397     const int buffSize = PARAM_NAME_LEN_MAX + PARAM_CONST_VALUE_LEN_MAX + 10;  // 10 max len
398     char *buffer = malloc(buffSize);
399     PARAM_CHECK(buffer != NULL, (void)fclose(fp);
400         return -1, "Failed to alloc memory");
401 
402     while (fgets(buffer, buffSize, fp) != NULL) {
403         buffer[buffSize - 1] = '\0';
404         int ret = SplitParamString(buffer, exclude, count, loadOneParam, &mode);
405         PARAM_ONLY_CHECK(ret != PARAM_DEFAULT_PARAM_MEMORY_NOT_ENOUGH, return PARAM_DEFAULT_PARAM_MEMORY_NOT_ENOUGH);
406         PARAM_CHECK(ret == 0, continue, "Failed to set param '%s' error:%d ", buffer, ret);
407         paramNum++;
408     }
409     (void)fclose(fp);
410     free(buffer);
411     PARAM_LOGV("Load %u default parameters success from %s.", paramNum, fileName);
412     return 0;
413 }
414 
ProcessParamFile(const char * fileName,void * context)415 static int ProcessParamFile(const char *fileName, void *context)
416 {
417     static const char *exclude[] = {"ctl.", "selinux.restorecon_recursive"};
418     uint32_t mode = *(int *)context;
419     int ret = LoadDefaultParam_(fileName, mode, exclude, ARRAY_LENGTH(exclude), LoadOneParam_);
420     if (ret == PARAM_DEFAULT_PARAM_MEMORY_NOT_ENOUGH) {
421         PARAM_LOGE("[startup_failed]default_param memory is not enough, system reboot! %d",SYS_PARAM_INIT_FAILED);
422         ExecReboot("panic");
423     }
424     return ret;
425 }
426 
LoadParamsFile(const char * fileName,bool onlyAdd)427 int LoadParamsFile(const char *fileName, bool onlyAdd)
428 {
429     return LoadDefaultParams(fileName, onlyAdd ? LOAD_PARAM_ONLY_ADD : LOAD_PARAM_NORMAL);
430 }
431 
LoadDefaultParams(const char * fileName,uint32_t mode)432 int LoadDefaultParams(const char *fileName, uint32_t mode)
433 {
434     PARAM_CHECK(fileName != NULL, return -1, "Invalid filename for load");
435     PARAM_LOGI("Load default parameters from %s.", fileName);
436     struct stat st;
437     if ((stat(fileName, &st) == 0) && !S_ISDIR(st.st_mode)) {
438         if (strstr(fileName, ".para.dac")) {
439             return LoadSecurityLabel(fileName);
440         } else {
441             return ProcessParamFile(fileName, &mode);
442         }
443     } else {
444         (void)ReadFileInDir(fileName, ".para", ProcessParamFile, &mode);
445         (void)ReadFileInDir(fileName, ".para.import", LoadParamFromImport, &mode);
446         return LoadSecurityLabel(fileName);
447     }
448 }
449 
LoadParamFromBuild(void)450 INIT_LOCAL_API void LoadParamFromBuild(void)
451 {
452     PARAM_LOGI("load parameters from build ");
453 #ifdef INCREMENTAL_VERSION
454     if (strlen(INCREMENTAL_VERSION) > 0) {
455         WriteParam("const.product.incremental.version", INCREMENTAL_VERSION, NULL, LOAD_PARAM_NORMAL);
456     }
457 #endif
458 #ifdef BUILD_TYPE
459     if (strlen(BUILD_TYPE) > 0) {
460         WriteParam("const.product.build.type", BUILD_TYPE, NULL, LOAD_PARAM_NORMAL);
461     }
462 #endif
463 #ifdef BUILD_USER
464     if (strlen(BUILD_USER) > 0) {
465         WriteParam("const.product.build.user", BUILD_USER, NULL, LOAD_PARAM_NORMAL);
466     }
467 #endif
468 #ifdef BUILD_TIME
469     if (strlen(BUILD_TIME) > 0) {
470         WriteParam("const.product.build.date", BUILD_TIME, NULL, LOAD_PARAM_NORMAL);
471     }
472 #endif
473 #ifdef BUILD_HOST
474     if (strlen(BUILD_HOST) > 0) {
475         WriteParam("const.product.build.host", BUILD_HOST, NULL, LOAD_PARAM_NORMAL);
476     }
477 #endif
478 #ifdef BUILD_ROOTHASH
479     if (strlen(BUILD_ROOTHASH) > 0) {
480         WriteParam("const.ohos.buildroothash", BUILD_ROOTHASH, NULL, LOAD_PARAM_NORMAL);
481     }
482 #endif
483 }
484 
LoadOneParamAreaSize_(const uint32_t * context,const char * name,const char * value)485 static int LoadOneParamAreaSize_(const uint32_t *context, const char *name, const char *value)
486 {
487     uint32_t size = (uint32_t)strtoul(value, NULL, DECIMAL_BASE);
488     PARAM_LOGV("LoadOneParamAreaSize_ [%s] [%s]", name, value);
489     ParamWorkSpace *paramSpace = GetParamWorkSpace();
490     PARAM_CHECK(paramSpace != NULL && paramSpace->workSpace != NULL,
491         return -1, "Invalid workspace name %s", name);
492     WorkSpaceSize *spaceSize = GetWorkSpaceSize(GetWorkSpace(WORKSPACE_INDEX_SIZE));
493     PARAM_CHECK(spaceSize != NULL, return PARAM_CODE_ERROR, "Failed to get workspace size");
494     static char buffer[SELINUX_CONTENT_LEN] = {0};
495     int ret = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "u:object_r:%s:s0", name);
496     PARAM_CHECK(ret > 0, return PARAM_CODE_ERROR, "Failed to snprintf workspace name");
497 
498     for (uint32_t i = WORKSPACE_INDEX_BASE + 1; i < spaceSize->maxLabelIndex; i++) {
499         if (paramSpace->workSpace[i] == NULL) {
500             continue;
501         }
502         if (strcmp(paramSpace->workSpace[i]->fileName, buffer) == 0) {
503             spaceSize->spaceSize[i] = size;
504             paramSpace->workSpace[i]->spaceSize = size;
505             break;
506         }
507     }
508     return 0;
509 }
510 
LoadParamAreaSize(void)511 INIT_LOCAL_API void LoadParamAreaSize(void)
512 {
513     LoadDefaultParam_("/sys_prod/etc/param/ohos.para.size", 0, NULL, 0, LoadOneParamAreaSize_);
514     LoadDefaultParam_(PARAM_AREA_SIZE_CFG, 0, NULL, 0, LoadOneParamAreaSize_);
515 }
516